]> git.saurik.com Git - apple/system_cmds.git/blob - mach_init.tproj/lists.c
ee1a008b298a7b0315a950d632a87f6eb41262fd
[apple/system_cmds.git] / mach_init.tproj / lists.c
1 /*
2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * bootstrap -- fundamental service initiator and port server
26 * Mike DeMoney, NeXT, Inc.
27 * Copyright, 1990. All rights reserved.
28 *
29 * lists.c -- implementation of list handling routines
30 */
31
32 #import <mach/boolean.h>
33 #import <mach/mach_error.h>
34
35 #import <stdlib.h>
36 #import <string.h>
37
38 #import "bootstrap_internal.h"
39 #import "lists.h"
40 #import "error_log.h"
41
42 /*
43 * Exports
44 */
45 bootstrap_info_t bootstraps; /* head of list of all bootstrap ports */
46 server_t servers; /* head of list of all servers */
47 service_t services; /* head of list of all services */
48 unsigned nservices; /* number of services in list */
49
50 #ifndef ASSERT
51 #define ASSERT(p)
52 #endif
53
54 /*
55 * Private macros
56 */
57 #define NEW(type, num) ((type *)ckmalloc(sizeof(type) * num))
58 #define STREQ(a, b) (strcmp(a, b) == 0)
59 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
60 #define LAST_ELEMENT(x) ((x)[NELEM(x)-1])
61
62 void
63 init_lists(void)
64 {
65 bootstraps.ref_count = 2; /* make sure we never deallocate this one */
66 bootstraps.next = bootstraps.prev = &bootstraps;
67 servers.next = servers.prev = &servers;
68 services.next = services.prev = &services;
69 nservices = 0;
70 }
71
72 server_t *
73 new_server(
74 bootstrap_info_t *bootstrap,
75 const char *cmd,
76 int uid,
77 servertype_t servertype)
78 {
79 server_t *serverp;
80
81 debug("adding new server \"%s\" with uid %d\n", cmd, uid);
82 serverp = NEW(server_t, 1);
83 if (serverp != NULL) {
84 /* Doubly linked list */
85 servers.prev->next = serverp;
86 serverp->prev = servers.prev;
87 serverp->next = &servers;
88 servers.prev = serverp;
89
90 bootstrap->ref_count++;
91 serverp->bootstrap = bootstrap;
92
93 serverp->pid = NO_PID;
94 serverp->task_port = MACH_PORT_NULL;
95 serverp->uid = uid;
96
97 serverp->port = MACH_PORT_NULL;
98 serverp->servertype = servertype;
99 serverp->activity = 0;
100 serverp->active_services = 0;
101 strncpy(serverp->cmd, cmd, sizeof serverp->cmd);
102 LAST_ELEMENT(serverp->cmd) = '\0';
103 }
104 return serverp;
105 }
106
107 service_t *
108 new_service(
109 bootstrap_info_t *bootstrap,
110 const char *name,
111 mach_port_t service_port,
112 boolean_t isActive,
113 servicetype_t servicetype,
114 server_t *serverp)
115 {
116 service_t *servicep;
117
118 servicep = NEW(service_t, 1);
119 if (servicep != NULL) {
120 /* Doubly linked list */
121 services.prev->next = servicep;
122 servicep->prev = services.prev;
123 servicep->next = &services;
124 services.prev = servicep;
125
126 nservices += 1;
127
128 strncpy(servicep->name, name, sizeof servicep->name);
129 LAST_ELEMENT(servicep->name) = '\0';
130 servicep->servicetype = servicetype;
131 servicep->bootstrap = bootstrap;
132 servicep->port = service_port;
133 servicep->server = serverp;
134 servicep->isActive = isActive;
135 }
136 return servicep;
137 }
138
139 bootstrap_info_t *
140 new_bootstrap(
141 bootstrap_info_t *parent,
142 mach_port_t bootstrap_port,
143 mach_port_t requestor_port)
144 {
145 bootstrap_info_t *bootstrap;
146
147 bootstrap = NEW(bootstrap_info_t, 1);
148 if (bootstrap != NULL) {
149 /* Doubly linked list */
150 bootstraps.prev->next = bootstrap;
151 bootstrap->prev = bootstraps.prev;
152 bootstrap->next = &bootstraps;
153 bootstraps.prev = bootstrap;
154
155 bootstrap->bootstrap_port = bootstrap_port;
156 bootstrap->requestor_port = requestor_port;
157
158 bootstrap->ref_count = 1;
159 bootstrap->parent = parent;
160 parent->ref_count++;
161 }
162 return bootstrap;
163 }
164
165 bootstrap_info_t *
166 lookup_bootstrap_by_port(mach_port_t port)
167 {
168 bootstrap_info_t *bootstrap;
169 bootstrap_info_t *first;
170 server_t *serverp;
171
172 bootstrap = first = FIRST(bootstraps);
173 do {
174 if (bootstrap->bootstrap_port == port)
175 return bootstrap;
176 bootstrap = NEXT(bootstrap);
177 } while (bootstrap != first);
178
179 for ( serverp = FIRST(servers)
180 ; !IS_END(serverp, servers)
181 ; serverp = NEXT(serverp))
182 {
183 if (port == serverp->port)
184 return serverp->bootstrap;
185 }
186 return NULL;
187 }
188
189 bootstrap_info_t *
190 lookup_bootstrap_by_req_port(mach_port_t port)
191 {
192 bootstrap_info_t *bootstrap;
193
194 for ( bootstrap = FIRST(bootstraps)
195 ; !IS_END(bootstrap, bootstraps)
196 ; bootstrap = NEXT(bootstrap))
197 {
198 if (bootstrap->requestor_port == port)
199 return bootstrap;
200 }
201
202 return NULL;
203 }
204
205 service_t *
206 lookup_service_by_name(bootstrap_info_t *bootstrap, name_t name)
207 {
208 service_t *servicep;
209
210 while (bootstrap) {
211 for ( servicep = FIRST(services)
212 ; !IS_END(servicep, services)
213 ; servicep = NEXT(servicep))
214 {
215 if (!STREQ(name, servicep->name))
216 continue;
217 if (bootstrap && servicep->bootstrap != bootstrap)
218 continue;
219 return servicep;
220 }
221 bootstrap = bootstrap->parent;
222 }
223
224 return NULL;
225 }
226
227 void
228 unlink_service(service_t *servicep)
229 {
230 ASSERT(servicep->prev->next == servicep);
231 ASSERT(servicep->next->prev == servicep);
232 servicep->prev->next = servicep->next;
233 servicep->next->prev = servicep->prev;
234 servicep->prev = servicep->next = servicep; // idempotent
235 }
236
237 void
238 delete_service(service_t *servicep)
239 {
240 unlink_service(servicep);
241 switch (servicep->servicetype) {
242 case REGISTERED:
243 info("Registered service %s deleted", servicep->name);
244 mach_port_deallocate(mach_task_self(), servicep->port);
245 break;
246 case DECLARED:
247 info("Declared service %s now unavailable", servicep->name);
248 mach_port_deallocate(mach_task_self(), servicep->port);
249 mach_port_mod_refs(mach_task_self(), servicep->port,
250 MACH_PORT_RIGHT_RECEIVE, -1);
251 break;
252 case SELF:
253 error("Self service %s now unavailable", servicep->name);
254 break;
255 default:
256 error("unknown service type %d\n", servicep->servicetype);
257 break;
258 }
259 free(servicep);
260 nservices -= 1;
261 }
262
263 void
264 delete_bootstrap_services(bootstrap_info_t *bootstrap)
265 {
266 server_t *serverp;
267 service_t *servicep;
268 service_t *next;
269
270 for ( servicep = FIRST(services)
271 ; !IS_END(servicep, services)
272 ; servicep = next)
273 {
274 next = NEXT(servicep);
275 if (bootstrap != servicep->bootstrap)
276 continue;
277
278 if (!servicep->isActive || !servicep->server) {
279 delete_service(servicep);
280 continue;
281 }
282
283 serverp = servicep->server;
284 delete_service(servicep);
285 serverp->active_services--;
286 if (!active_server(serverp))
287 delete_server(serverp);
288 }
289 }
290
291 service_t *
292 lookup_service_by_port(mach_port_t port)
293 {
294 service_t *servicep;
295
296 for ( servicep = FIRST(services)
297 ; !IS_END(servicep, services)
298 ; servicep = NEXT(servicep))
299 {
300 if (port == servicep->port)
301 return servicep;
302 }
303 return NULL;
304 }
305
306 service_t *
307 lookup_service_by_server(server_t *serverp)
308 {
309 service_t *servicep;
310
311 for ( servicep = FIRST(services)
312 ; !IS_END(servicep, services)
313 ; servicep = NEXT(servicep))
314 {
315 if (serverp == servicep->server)
316 return servicep;
317 }
318 return NULL;
319 }
320
321 server_t *
322 lookup_server_by_task_port(mach_port_t port)
323 {
324 server_t *serverp;
325
326 for ( serverp = FIRST(servers)
327 ; !IS_END(serverp, servers)
328 ; serverp = NEXT(serverp))
329 {
330 if (port == serverp->task_port)
331 return serverp;
332 }
333 return NULL;
334 }
335
336 server_t *
337 lookup_server_by_port(mach_port_t port)
338 {
339 server_t *serverp;
340
341 for ( serverp = FIRST(servers)
342 ; !IS_END(serverp, servers)
343 ; serverp = NEXT(serverp))
344 {
345 if (port == serverp->port)
346 return serverp;
347 }
348 return NULL;
349 }
350
351 void
352 delete_server(server_t *serverp)
353 {
354 service_t *servicep;
355 service_t *next;
356
357 info("Deleting server %s", serverp->cmd);
358 ASSERT(serverp->prev->next == serverp);
359 ASSERT(serverp->next->prev == serverp);
360 serverp->prev->next = serverp->next;
361 serverp->next->prev = serverp->prev;
362
363 for ( servicep = FIRST(services)
364 ; !IS_END(servicep, services)
365 ; servicep = next)
366 {
367 next = NEXT(servicep);
368 if (serverp == servicep->server)
369 delete_service(servicep);
370 }
371
372 deallocate_bootstrap(serverp->bootstrap);
373
374 #ifndef DELAYED_BOOTSTRAP_DESTROY
375 if (serverp->port)
376 mach_port_mod_refs(mach_task_self(), serverp->port,
377 MACH_PORT_RIGHT_RECEIVE, -1);
378 #endif
379
380 free(serverp);
381 }
382
383 void
384 deactivate_bootstrap(bootstrap_info_t *bootstrap)
385 {
386 bootstrap_info_t *deactivating_bootstraps;
387 bootstrap_info_t *query_bootstrap;
388 bootstrap_info_t *next_limit;
389 bootstrap_info_t *limit;
390
391 /*
392 * we need to recursively deactivate the whole subset tree below
393 * this point. But we don't want to do real recursion because
394 * we don't have a limit on the depth. So, build up a chain of
395 * active bootstraps anywhere underneath this one.
396 */
397 deactivating_bootstraps = bootstrap;
398 bootstrap->deactivate = NULL;
399 for (next_limit = deactivating_bootstraps, limit = NULL
400 ; deactivating_bootstraps != limit
401 ; limit = next_limit, next_limit = deactivating_bootstraps)
402 {
403 for (bootstrap = deactivating_bootstraps
404 ; bootstrap != limit
405 ; bootstrap = bootstrap->deactivate)
406 {
407 for ( query_bootstrap = FIRST(bootstraps)
408 ; !IS_END(query_bootstrap, bootstraps)
409 ; query_bootstrap = NEXT(query_bootstrap))
410 {
411 if (query_bootstrap->parent == bootstrap &&
412 query_bootstrap->requestor_port != MACH_PORT_NULL) {
413 mach_port_deallocate(
414 mach_task_self(),
415 query_bootstrap->requestor_port);
416 query_bootstrap->requestor_port = MACH_PORT_NULL;
417 query_bootstrap->deactivate = deactivating_bootstraps;
418 deactivating_bootstraps = query_bootstrap;
419 }
420 }
421 }
422 }
423
424 /*
425 * The list is ordered with the furthest away progeny being
426 * at the front, and concluding with the one we started with.
427 * This allows us to safely deactivate and remove the reference
428 * each holds on their parent without fear of the chain getting
429 * corrupted (because each active parent holds a reference on
430 * itself and that doesn't get removed until we reach its spot
431 * in the list).
432 */
433 do {
434 bootstrap = deactivating_bootstraps;
435 deactivating_bootstraps = bootstrap->deactivate;
436
437 info("deactivating bootstrap %x", bootstrap->bootstrap_port);
438
439 delete_bootstrap_services(bootstrap);
440
441 mach_port_deallocate(mach_task_self(), bootstrap->bootstrap_port);
442
443 #ifdef DELAYED_BOOTSTRAP_DESTROY
444 {
445 mach_port_t previous;
446 mach_port_request_notification(
447 mach_task_self(),
448 bootstrap->bootstrap_port,
449 MACH_NOTIFY_NO_SENDERS,
450 1,
451 bootstrap->bootstrap_port,
452 MACH_MSG_TYPE_MAKE_SEND_ONCE,
453 &previous);
454 }
455 #else
456 mach_port_mod_refs(
457 mach_task_self(),
458 bootstrap->bootstrap_port,
459 MACH_PORT_RIGHT_RECEIVE,
460 -1);
461 bootstrap->bootstrap_port = MACH_PORT_NULL;
462 deallocate_bootstrap(bootstrap);
463 #endif
464
465 } while (deactivating_bootstraps != NULL);
466 }
467
468 void
469 deallocate_bootstrap(bootstrap_info_t *bootstrap)
470 {
471 ASSERT(bootstrap->prev->next == bootstrap);
472 ASSERT(bootstrap->next->prev == bootstrap);
473 if (--bootstrap->ref_count > 0)
474 return;
475
476 bootstrap->prev->next = bootstrap->next;
477 bootstrap->next->prev = bootstrap->prev;
478 deallocate_bootstrap(bootstrap->parent);
479 free(bootstrap);
480 }
481
482 void *
483 ckmalloc(unsigned nbytes)
484 {
485 void *cp;
486
487 if ((cp = malloc(nbytes)) == NULL)
488 fatal("Out of memory");
489 return cp;
490 }
491
492