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