FreeBSD/Linux Kernel Cross Reference
sys/norma/ipc_list.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1992 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_list.c,v $
29 * Revision 2.3 93/05/15 19:35:22 mrt
30 * machparam.h -> machspl.h
31 *
32 * Revision 2.2 92/03/10 16:27:38 jsb
33 * Merged in norma branch changes as of NORMA_MK7.
34 * [92/03/09 12:49:22 jsb]
35 *
36 * Revision 2.1.1.7.1.5 92/02/22 10:44:15 jsb
37 * Temporary workaround: changed "not tabled" panic to a printf.
38 *
39 * Revision 2.1.1.7.1.4 92/02/21 11:24:24 jsb
40 * Added new routine norma_port_remove_try.
41 * [92/02/20 17:15:49 jsb]
42 *
43 * Added db_show_{uid,all_uids}_verbose.
44 * [92/02/20 10:33:47 jsb]
45 *
46 * Revision 2.1.1.7.1.3 92/01/21 21:51:19 jsb
47 * Now uses hash table. Now uses netipc lock instead of spls.
48 * Removed seqno debugging hack. Added norma_port_iterate and
49 * reimplemented db_show_uid (nee norma_list_all_ports) with it.
50 * Added support for show all {proxies, principals}. Use kdbprintf
51 * instead of printf for these routines for pagination.
52 * [92/01/16 22:46:09 jsb]
53 *
54 * Revision 2.1.1.7.1.2 92/01/03 16:37:27 jsb
55 * Use ipc_port_release instead of ip_release to allow port deallocation.
56 * [91/12/31 21:42:40 jsb]
57 *
58 * Added norma_port_tabled function.
59 * [91/12/31 17:17:02 jsb]
60 *
61 * In norma_port_remove, refuse to remove a proxy that started out as a
62 * principal, since our forwarding algorithms require it to stay around.
63 * [91/12/31 12:19:08 jsb]
64 *
65 * Hacked norma_new_uid to incorporate incarnation in generated uids.
66 * Threw in a stub for norma_ipc_cleanup_incarnation.
67 * [91/12/29 16:08:32 jsb]
68 *
69 * Lots of ugly but useful debugging support.
70 * [91/12/28 18:45:37 jsb]
71 *
72 * Made norma_list_all_ports print port addresses as well as uids.
73 * [91/12/25 16:57:46 jsb]
74 *
75 * First checkin. Split from norma/ipc_transit.c.
76 * [91/12/24 14:26:58 jsb]
77 *
78 * Revision 2.1.1.7.1.1 92/01/03 08:54:06 jsb
79 * First NORMA branch checkin.
80 *
81 *
82 */
83 /*
84 * File: norma/ipc_list.c
85 * Author: Joseph S. Barrera III
86 * Date: 1991
87 *
88 * Maintains list of norma ports.
89 */
90
91 #include <machine/machspl.h>
92 #include <ipc/ipc_port.h>
93 #include <norma/ipc_node.h>
94
95 extern void netipc_thread_lock();
96 extern void netipc_thread_unlock();
97
98 /*
99 * Definitions for norma special ports.
100 */
101 unsigned long lid_counter = 0;
102 extern unsigned long node_incarnation;
103 extern ipc_port_t host_special_port[MAX_SPECIAL_ID];
104
105 /*
106 * Allocate a uid for a newly exported port.
107 */
108 unsigned long
109 norma_new_uid_locked()
110 {
111 if (lid_counter == 0) {
112 /*
113 * XXX
114 * This is a hack to work the incarnation into the lid
115 * so that we don't recreate the same uids. I still need
116 * to figure out how to do norma_ipc_cleanup_incarnation
117 * for real.
118 */
119 lid_counter = MAX_SPECIAL_ID +
120 (node_incarnation % 16) * ((IP_NORMA_MAX_LID + 1) / 16);
121 printf1("*** first uid=%x\n",
122 IP_NORMA_UID(node_self(), lid_counter));
123 } else if (lid_counter == IP_NORMA_MAX_LID) {
124 panic("norma_new_uid: ran out of local ids\n");
125 }
126 return IP_NORMA_UID(node_self(), lid_counter++);
127 }
128
129 norma_ipc_cleanup_incarnation(remote)
130 unsigned long remote;
131 {
132 /*
133 * XXX
134 * What exactly do we clean up???
135 */
136 }
137
138 #define HASH_SIZE 16 /* must be power of two */
139 #define HASH_MASK (HASH_SIZE - 1)
140 #define UID_HASH(uid) ((IP_NORMA_NODE(uid) + IP_NORMA_LID(uid)) & HASH_MASK)
141
142 ipc_port_t norma_port_table[HASH_SIZE];
143
144 int c_norma_port_lookup = 0;
145 int c_norma_port_insert = 0;
146 int c_norma_port_remove = 0;
147
148 /*
149 * We currently use a fairly conservative locking strategy, in which we
150 * always grab the netipc_lock before inserts, removals, and lookups.
151 * We could do better once we move port removal out of norma_ipc_receive_dest,
152 * at which point only port lookups would be done at interrupt level.
153 * At this point, we could use a simple lock for lookups and only
154 * use netipc_lock (in combination with the simple lock) for inserts and
155 * removals. Currently this doesn't buy you much because send-once rights
156 * are continually being inserted and removed; if we added a bit of laziness
157 * to send-once right handling, then presumably lookups would dominate
158 * inserts and removals.
159 */
160
161 boolean_t
162 norma_port_tabled(port)
163 ipc_port_t port;
164 {
165 return (port->ip_norma_next != port);
166 }
167
168 ipc_port_t
169 norma_port_lookup_locked(uid)
170 register unsigned long uid;
171 {
172 register ipc_port_t p;
173
174 c_norma_port_lookup++;
175 if (uid == 0) {
176 return IP_NULL;
177 }
178 for (p = norma_port_table[UID_HASH(uid)]; p; p = p->ip_norma_next) {
179 if (p->ip_norma_uid == uid) {
180 return p;
181 }
182 }
183 return IP_NULL;
184 }
185
186 void
187 norma_port_insert_locked(port)
188 register ipc_port_t port;
189 {
190 register ipc_port_t *bucket;
191 register unsigned long uid;
192
193 c_norma_port_insert++;
194 if (norma_port_tabled(port)) {
195 panic("norma_port_insert: tabled!\n");
196 return;
197 }
198 uid = port->ip_norma_uid;
199 assert(uid != 0);
200 bucket = &norma_port_table[UID_HASH(uid)];
201 port->ip_norma_next = *bucket;
202 *bucket = port;
203 ip_reference(port);
204 }
205
206 void
207 norma_port_remove_locked(port)
208 register ipc_port_t port;
209 {
210 register unsigned long uid;
211 register ipc_port_t p, *pp;
212
213 c_norma_port_remove++;
214 if (! norma_port_tabled(port)) {
215 /* XXX should be a panic */
216 printf("norma_port_remote: not tabled!\n");
217 return;
218 }
219 uid = port->ip_norma_uid;
220 assert(uid != 0);
221
222 /*
223 * This is kind of gross.
224 * We cannot remove a proxy that started out as a principal;
225 * it must stay around to do forwarding.
226 */
227 if (port->ip_norma_is_proxy && IP_NORMA_NODE(uid) == node_self()) {
228 printf1("norma_port_remove: not removing port %x\n", port);
229 return;
230 }
231
232 /*
233 * We can go ahead now.
234 */
235 pp = &norma_port_table[UID_HASH(uid)];
236 for (p = *pp; p; pp = &p->ip_norma_next, p = *pp) {
237 if (p == port) {
238 *pp = port->ip_norma_next;
239 port->ip_norma_next = port;
240 printf1("norma_port_remove(0x%x:%x): refs %d\n",
241 port, uid, port->ip_references - 1);
242 ipc_port_release(port);
243 return;
244 }
245 }
246 panic("norma_port_remove(0x%x:%x): not found\n", port, uid);
247 }
248
249 ipc_port_t
250 norma_port_lookup(uid)
251 register unsigned long uid;
252 {
253 register ipc_port_t port;
254
255 assert(! netipc_locked());
256 netipc_thread_lock();
257 port = norma_port_lookup_locked(uid);
258 netipc_thread_unlock();
259 return port;
260 }
261
262 void
263 norma_port_insert(port)
264 register ipc_port_t port;
265 {
266 assert(! netipc_locked());
267 netipc_thread_lock();
268 norma_port_insert_locked(port);
269 netipc_thread_unlock();
270 }
271
272 void
273 norma_port_remove(port)
274 register ipc_port_t port;
275 {
276 assert(! netipc_locked());
277 netipc_thread_lock();
278 norma_port_remove_locked(port);
279 netipc_thread_unlock();
280 }
281
282 void
283 norma_port_remove_try(port)
284 register ipc_port_t port;
285 {
286 if (port->ip_srights == 0 && port->ip_sorights == 0) {
287 printf1("norma_port_remove_try: releasing 0x%x:%x\n",
288 port, port->ip_norma_uid);
289 assert(! netipc_locked());
290 netipc_thread_lock();
291 norma_port_remove_locked(port);
292 netipc_thread_unlock();
293 }
294 }
295
296 unsigned long
297 norma_new_uid()
298 {
299 register unsigned long uid;
300
301 assert(! netipc_locked());
302 netipc_thread_lock();
303 uid = norma_new_uid_locked();
304 netipc_thread_unlock();
305 return uid;
306 }
307
308 norma_port_table_statistics()
309 {
310 int i, total, average, len, longest;
311 int l1, l2, l3;
312 ipc_port_t p;
313
314 total = 0;
315 for (i = 0; i < HASH_SIZE; i++) {
316 for (p = norma_port_table[i]; p; p = p->ip_norma_next) {
317 total++;
318 }
319 }
320 average = total / HASH_SIZE;
321 if (average == 0) {
322 average = 1;
323 }
324 longest = l1 = l2 = l3 = 0;
325 for (i = 0; i < HASH_SIZE; i++) {
326 len = 0;
327 for (p = norma_port_table[i]; p; p = p->ip_norma_next) {
328 len++;
329 }
330 if (longest < len) {
331 longest = len;
332 }
333 if (len > average) {
334 l1++;
335 if (len > 2 * average) {
336 l2++;
337 if (len > 3 * average) {
338 l3++;
339 }
340 }
341 }
342 }
343 kdbprintf("%d ports, %d buckets, average %d per bucket\n",
344 total, HASH_SIZE, total / HASH_SIZE);
345 kdbprintf("%d chains longer than %d, %d > %d, %d > %d; longest = %d\n",
346 l1, average, l2, 2 * average, l3, 3 * average, longest);
347 }
348
349 norma_port_iterate(function, args)
350 void (*function)();
351 void *args;
352 {
353 int i;
354 ipc_port_t p;
355
356 for (i = 0; i < HASH_SIZE; i++) {
357 for (p = norma_port_table[i]; p; p = p->ip_norma_next) {
358 (*function)(p, args);
359 }
360 }
361 (*function)(IP_NULL, args);
362 }
363
364 #include <ddb/db_sym.h>
365
366 void
367 db_show_uid(port, args)
368 ipc_port_t port;
369 void *args;
370 {
371 int *countp = (int *) args;
372
373 if (port == IP_NULL) {
374 printf("\n");
375 return;
376 }
377 if (++*countp == 4) {
378 kdbprintf("%x:%x\n", port, port->ip_norma_uid);
379 *countp = 0;
380 } else {
381 kdbprintf("%x:%x ", port, port->ip_norma_uid);
382 }
383 }
384
385 void
386 db_show_uid_verbose(port, args)
387 ipc_port_t port;
388 void *args;
389 {
390 if (port == IP_NULL) {
391 return;
392 }
393 kdbprintf("%x:%x %6d ",
394 port, port->ip_norma_uid, port->ip_norma_spare2);
395 db_printsym(port->ip_norma_spare1, DB_STGY_PROC);
396 kdbprintf("\n");
397 }
398
399 void
400 db_show_proxy(port, args)
401 ipc_port_t port;
402 void *args;
403 {
404 if (port == IP_NULL || port->ip_norma_is_proxy) {
405 db_show_uid(port, args);
406 }
407 }
408
409 void
410 db_show_principal(port, args)
411 ipc_port_t port;
412 void *args;
413 {
414 if (port == IP_NULL || ! port->ip_norma_is_proxy) {
415 db_show_uid(port, args);
416 }
417 }
418
419 db_show_all_uids()
420 {
421 int count = 0;
422
423 norma_port_table_statistics();
424 norma_port_iterate(db_show_uid, (void *) &count);
425 }
426
427 db_show_all_uids_verbose()
428 {
429 norma_port_table_statistics();
430 norma_port_iterate(db_show_uid_verbose, (void *) 0);
431 }
432
433 db_show_all_proxies()
434 {
435 int count = 0;
436
437 norma_port_iterate(db_show_proxy, (void *) &count);
438 }
439
440 db_show_all_principals()
441 {
442 int count = 0;
443
444 norma_port_iterate(db_show_principal, (void *) &count);
445 }
Cache object: 18e4720383fbe8df4efb9b331e295453
|