1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: ipc_marequest.c,v $
29 * Revision 2.10 93/03/09 10:54:41 danner
30 * Added typecast in hashing macros to shutup GCC.
31 * [93/03/06 af]
32 *
33 * Revision 2.9 92/08/03 17:34:37 jfriedl
34 * removed silly prototypes
35 * [92/08/02 jfriedl]
36 *
37 * Revision 2.8 92/05/21 17:10:37 jfriedl
38 * tried prototypes.
39 * [92/05/20 jfriedl]
40 *
41 * Revision 2.7 92/01/14 16:44:37 rpd
42 * Changed ipc_marequest_info for CountInOut.
43 * [92/01/14 rpd]
44 *
45 * Revision 2.6 91/05/14 16:33:35 mrt
46 * Correcting copyright
47 *
48 * Revision 2.5 91/02/05 17:22:13 mrt
49 * Changed to new Mach copyright
50 * [91/02/01 15:46:05 mrt]
51 *
52 * Revision 2.4 91/01/08 15:14:11 rpd
53 * Changed ipc_info_bucket_t to hash_info_bucket_t.
54 * [91/01/02 rpd]
55 *
56 * Changed zchange calls to make the IPC zones non-collectable.
57 * [90/12/29 rpd]
58 *
59 * Revision 2.3 90/12/20 16:38:53 jeffreyh
60 * Change zchange to match new number of arguments.
61 * Made zone collectable.
62 * [90/12/11 jeffreyh]
63 *
64 * Revision 2.2 90/06/02 14:50:30 rpd
65 * Created for new IPC.
66 * [90/03/26 20:56:33 rpd]
67 *
68 */
69 /*
70 * File: ipc/ipc_marequest.c
71 * Author: Rich Draves
72 * Date: 1989
73 *
74 * Functions to handle msg-accepted requests.
75 */
76
77 #include <mach_ipc_compat.h>
78
79 #include <mach/message.h>
80 #include <mach/port.h>
81 #include <kern/lock.h>
82 #include <kern/mach_param.h>
83 #include <kern/kalloc.h>
84 #include <kern/zalloc.h>
85 #include <ipc/port.h>
86 #include <ipc/ipc_space.h>
87 #include <ipc/ipc_entry.h>
88 #include <ipc/ipc_port.h>
89 #include <ipc/ipc_right.h>
90 #include <ipc/ipc_marequest.h>
91 #include <ipc/ipc_notify.h>
92
93 #include <mach_ipc_debug.h>
94 #if MACH_IPC_DEBUG
95 #include <mach/kern_return.h>
96 #include <mach_debug/hash_info.h>
97 #include <vm/vm_map.h>
98 #include <vm/vm_kern.h>
99 #include <vm/vm_user.h>
100 #endif
101
102
103 zone_t ipc_marequest_zone;
104 int ipc_marequest_max = IMAR_MAX;
105
106 #define imar_alloc() ((ipc_marequest_t) zalloc(ipc_marequest_zone))
107 #define imar_free(imar) zfree(ipc_marequest_zone, (vm_offset_t) (imar))
108
109 typedef unsigned int ipc_marequest_index_t;
110
111 ipc_marequest_index_t ipc_marequest_size;
112 ipc_marequest_index_t ipc_marequest_mask;
113
114 #define IMAR_HASH(space, name) \
115 ((((ipc_marequest_index_t)((vm_offset_t)space) >> 4) + \
116 MACH_PORT_INDEX(name) + MACH_PORT_NGEN(name)) & \
117 ipc_marequest_mask)
118
119 typedef struct ipc_marequest_bucket {
120 decl_simple_lock_data(, imarb_lock_data)
121 ipc_marequest_t imarb_head;
122 } *ipc_marequest_bucket_t;
123
124 #define IMARB_NULL ((ipc_marequest_bucket_t) 0)
125
126 #define imarb_lock_init(imarb) simple_lock_init(&(imarb)->imarb_lock_data)
127 #define imarb_lock(imarb) simple_lock(&(imarb)->imarb_lock_data)
128 #define imarb_unlock(imarb) simple_unlock(&(imarb)->imarb_lock_data)
129
130 ipc_marequest_bucket_t ipc_marequest_table;
131
132
133
134 /*
135 * Routine: ipc_marequest_init
136 * Purpose:
137 * Initialize the msg-accepted request module.
138 */
139
140 void
141 ipc_marequest_init()
142 {
143 ipc_marequest_index_t i;
144
145 /* if not configured, initialize ipc_marequest_size */
146
147 if (ipc_marequest_size == 0) {
148 ipc_marequest_size = ipc_marequest_max >> 8;
149 if (ipc_marequest_size < 16)
150 ipc_marequest_size = 16;
151 }
152
153 /* make sure it is a power of two */
154
155 ipc_marequest_mask = ipc_marequest_size - 1;
156 if ((ipc_marequest_size & ipc_marequest_mask) != 0) {
157 unsigned int bit;
158
159 /* round up to closest power of two */
160
161 for (bit = 1;; bit <<= 1) {
162 ipc_marequest_mask |= bit;
163 ipc_marequest_size = ipc_marequest_mask + 1;
164
165 if ((ipc_marequest_size & ipc_marequest_mask) == 0)
166 break;
167 }
168 }
169
170 /* allocate ipc_marequest_table */
171
172 ipc_marequest_table = (ipc_marequest_bucket_t)
173 kalloc((vm_size_t) (ipc_marequest_size *
174 sizeof(struct ipc_marequest_bucket)));
175 assert(ipc_marequest_table != IMARB_NULL);
176
177 /* and initialize it */
178
179 for (i = 0; i < ipc_marequest_size; i++) {
180 ipc_marequest_bucket_t bucket;
181
182 bucket = &ipc_marequest_table[i];
183 imarb_lock_init(bucket);
184 bucket->imarb_head = IMAR_NULL;
185 }
186
187 ipc_marequest_zone =
188 zinit(sizeof(struct ipc_marequest),
189 ipc_marequest_max * sizeof(struct ipc_marequest),
190 sizeof(struct ipc_marequest),
191 FALSE, "ipc msg-accepted requests");
192 /* make it exhaustible */
193 zchange(ipc_marequest_zone, FALSE, FALSE, TRUE, FALSE);
194 }
195
196 /*
197 * Routine: ipc_marequest_create
198 * Purpose:
199 * Create a msg-accepted request, because
200 * a sender is forcing a message with MACH_SEND_NOTIFY.
201 *
202 * The "notify" argument should name a receive right
203 * that is used to create the send-once notify port.
204 *
205 * [MACH_IPC_COMPAT] If "notify" is MACH_PORT_NULL,
206 * then an old-style msg-accepted request is created.
207 * Conditions:
208 * Nothing locked; refs held for space and port.
209 * Returns:
210 * MACH_MSG_SUCCESS Msg-accepted request created.
211 * MACH_SEND_INVALID_NOTIFY The space is dead.
212 * MACH_SEND_INVALID_NOTIFY The notify port is bad.
213 * MACH_SEND_NOTIFY_IN_PROGRESS
214 * This space has already forced a message to this port.
215 * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
216 */
217
218 mach_msg_return_t
219 ipc_marequest_create(space, port, notify, marequestp)
220 ipc_space_t space;
221 ipc_port_t port;
222 mach_port_t notify;
223 ipc_marequest_t *marequestp;
224 {
225 mach_port_t name;
226 ipc_entry_t entry;
227 ipc_port_t soright;
228 ipc_marequest_t marequest;
229 ipc_marequest_bucket_t bucket;
230
231 #if !MACH_IPC_COMPAT
232 assert(notify != MACH_PORT_NULL);
233 #endif !MACH_IPC_COMPAT
234
235 marequest = imar_alloc();
236 if (marequest == IMAR_NULL)
237 return MACH_SEND_NO_NOTIFY;
238
239 /*
240 * Delay creating the send-once right until
241 * we know there will be no errors. Otherwise,
242 * we would have to worry about disposing of it
243 * when it turned out it wasn't needed.
244 */
245
246 is_write_lock(space);
247 if (!space->is_active) {
248 is_write_unlock(space);
249 imar_free(marequest);
250 return MACH_SEND_INVALID_NOTIFY;
251 }
252
253 if (ipc_right_reverse(space, (ipc_object_t) port, &name, &entry)) {
254 ipc_entry_bits_t bits;
255
256 /* port is locked and active */
257 ip_unlock(port);
258 bits = entry->ie_bits;
259
260 assert(port == (ipc_port_t) entry->ie_object);
261 assert(bits & MACH_PORT_TYPE_SEND_RECEIVE);
262
263 if (bits & IE_BITS_MAREQUEST) {
264 is_write_unlock(space);
265 imar_free(marequest);
266 return MACH_SEND_NOTIFY_IN_PROGRESS;
267 }
268
269 #if MACH_IPC_COMPAT
270 if (notify == MACH_PORT_NULL)
271 soright = IP_NULL;
272 else
273 #endif MACH_IPC_COMPAT
274 if ((soright = ipc_port_lookup_notify(space, notify))
275 == IP_NULL) {
276 is_write_unlock(space);
277 imar_free(marequest);
278 return MACH_SEND_INVALID_NOTIFY;
279 }
280
281 entry->ie_bits = bits | IE_BITS_MAREQUEST;
282
283 is_reference(space);
284 marequest->imar_space = space;
285 marequest->imar_name = name;
286 marequest->imar_soright = soright;
287
288 bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
289 imarb_lock(bucket);
290
291 marequest->imar_next = bucket->imarb_head;
292 bucket->imarb_head = marequest;
293
294 imarb_unlock(bucket);
295 } else {
296 #if MACH_IPC_COMPAT
297 if (notify == MACH_PORT_NULL)
298 soright = IP_NULL;
299 else
300 #endif MACH_IPC_COMPAT
301 if ((soright = ipc_port_lookup_notify(space, notify))
302 == IP_NULL) {
303 is_write_unlock(space);
304 imar_free(marequest);
305 return MACH_SEND_INVALID_NOTIFY;
306 }
307
308 is_reference(space);
309 marequest->imar_space = space;
310 marequest->imar_name = MACH_PORT_NULL;
311 marequest->imar_soright = soright;
312 }
313
314 is_write_unlock(space);
315 *marequestp = marequest;
316 return MACH_MSG_SUCCESS;
317 }
318
319 /*
320 * Routine: ipc_marequest_cancel
321 * Purpose:
322 * Cancel a msg-accepted request, because
323 * the space's entry is being destroyed.
324 * Conditions:
325 * The space is write-locked and active.
326 */
327
328 void
329 ipc_marequest_cancel(space, name)
330 ipc_space_t space;
331 mach_port_t name;
332 {
333 ipc_marequest_bucket_t bucket;
334 ipc_marequest_t marequest, *last;
335
336 assert(space->is_active);
337
338 bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
339 imarb_lock(bucket);
340
341 for (last = &bucket->imarb_head;
342 (marequest = *last) != IMAR_NULL;
343 last = &marequest->imar_next)
344 if ((marequest->imar_space == space) &&
345 (marequest->imar_name == name))
346 break;
347
348 assert(marequest != IMAR_NULL);
349 *last = marequest->imar_next;
350 imarb_unlock(bucket);
351
352 marequest->imar_name = MACH_PORT_NULL;
353 }
354
355 /*
356 * Routine: ipc_marequest_rename
357 * Purpose:
358 * Rename a msg-accepted request, because the entry
359 * in the space is being renamed.
360 * Conditions:
361 * The space is write-locked and active.
362 */
363
364 void
365 ipc_marequest_rename(space, old, new)
366 ipc_space_t space;
367 mach_port_t old, new;
368 {
369 ipc_marequest_bucket_t bucket;
370 ipc_marequest_t marequest, *last;
371
372 assert(space->is_active);
373
374 bucket = &ipc_marequest_table[IMAR_HASH(space, old)];
375 imarb_lock(bucket);
376
377 for (last = &bucket->imarb_head;
378 (marequest = *last) != IMAR_NULL;
379 last = &marequest->imar_next)
380 if ((marequest->imar_space == space) &&
381 (marequest->imar_name == old))
382 break;
383
384 assert(marequest != IMAR_NULL);
385 *last = marequest->imar_next;
386 imarb_unlock(bucket);
387
388 marequest->imar_name = new;
389
390 bucket = &ipc_marequest_table[IMAR_HASH(space, new)];
391 imarb_lock(bucket);
392
393 marequest->imar_next = bucket->imarb_head;
394 bucket->imarb_head = marequest;
395
396 imarb_unlock(bucket);
397 }
398
399 /*
400 * Routine: ipc_marequest_destroy
401 * Purpose:
402 * Destroy a msg-accepted request, because
403 * the kernel message is being received/destroyed.
404 * Conditions:
405 * Nothing locked.
406 */
407
408 void
409 ipc_marequest_destroy(marequest)
410 ipc_marequest_t marequest;
411 {
412 ipc_space_t space = marequest->imar_space;
413 mach_port_t name;
414 ipc_port_t soright;
415 #if MACH_IPC_COMPAT
416 ipc_port_t sright = IP_NULL;
417 #endif MACH_IPC_COMPAT
418
419 is_write_lock(space);
420
421 name = marequest->imar_name;
422 soright = marequest->imar_soright;
423
424 if (name != MACH_PORT_NULL) {
425 ipc_marequest_bucket_t bucket;
426 ipc_marequest_t this, *last;
427
428 bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
429 imarb_lock(bucket);
430
431 for (last = &bucket->imarb_head;
432 (this = *last) != IMAR_NULL;
433 last = &this->imar_next)
434 if ((this->imar_space == space) &&
435 (this->imar_name == name))
436 break;
437
438 assert(this == marequest);
439 *last = this->imar_next;
440 imarb_unlock(bucket);
441
442 if (space->is_active) {
443 ipc_entry_t entry;
444
445 entry = ipc_entry_lookup(space, name);
446 assert(entry != IE_NULL);
447 assert(entry->ie_bits & IE_BITS_MAREQUEST);
448 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
449
450 entry->ie_bits &= ~IE_BITS_MAREQUEST;
451
452 #if MACH_IPC_COMPAT
453 if (soright == IP_NULL)
454 sright = ipc_space_make_notify(space);
455 #endif MACH_IPC_COMPAT
456 } else
457 name = MACH_PORT_NULL;
458 }
459
460 is_write_unlock(space);
461 is_release(space);
462
463 imar_free(marequest);
464
465 #if MACH_IPC_COMPAT
466 if (soright == IP_NULL) {
467 if (IP_VALID(sright)) {
468 assert(name != MACH_PORT_NULL);
469 ipc_notify_msg_accepted_compat(sright, name);
470 }
471
472 return;
473 }
474 assert(sright == IP_NULL);
475 #endif MACH_IPC_COMPAT
476
477 assert(soright != IP_NULL);
478 ipc_notify_msg_accepted(soright, name);
479 }
480
481 #if MACH_IPC_DEBUG
482
483
484 /*
485 * Routine: ipc_marequest_info
486 * Purpose:
487 * Return information about the marequest hash table.
488 * Fills the buffer with as much information as possible
489 * and returns the desired size of the buffer.
490 * Conditions:
491 * Nothing locked. The caller should provide
492 * possibly-pageable memory.
493 */
494
495 unsigned int
496 ipc_marequest_info(maxp, info, count)
497 unsigned int *maxp;
498 hash_info_bucket_t *info;
499 unsigned int count;
500 {
501 ipc_marequest_index_t i;
502
503 if (ipc_marequest_size < count)
504 count = ipc_marequest_size;
505
506 for (i = 0; i < count; i++) {
507 ipc_marequest_bucket_t bucket = &ipc_marequest_table[i];
508 unsigned int bucket_count = 0;
509 ipc_marequest_t marequest;
510
511 imarb_lock(bucket);
512 for (marequest = bucket->imarb_head;
513 marequest != IMAR_NULL;
514 marequest = marequest->imar_next)
515 bucket_count++;
516 imarb_unlock(bucket);
517
518 /* don't touch pageable memory while holding locks */
519 info[i].hib_count = bucket_count;
520 }
521
522 *maxp = ipc_marequest_max;
523 return ipc_marequest_size;
524 }
525
526 #endif MACH_IPC_DEBUG
Cache object: 4f9949691d92e3e0acf0a559640e7b39
|