]> git.saurik.com Git - apple/system_cmds.git/blame - mach_init.tproj/lists.c
system_cmds-230.tar.gz
[apple/system_cmds.git] / mach_init.tproj / lists.c
CommitLineData
1815bff5 1/*
b51d5b5f 2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
1815bff5
A
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 */
45bootstrap_info_t bootstraps; /* head of list of all bootstrap ports */
46server_t servers; /* head of list of all servers */
47service_t services; /* head of list of all services */
48unsigned 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
62void
63init_lists(void)
64{
b51d5b5f 65 bootstraps.ref_count = 2; /* make sure we never deallocate this one */
1815bff5
A
66 bootstraps.next = bootstraps.prev = &bootstraps;
67 servers.next = servers.prev = &servers;
68 services.next = services.prev = &services;
69 nservices = 0;
70}
71
72server_t *
73new_server(
b51d5b5f
A
74 bootstrap_info_t *bootstrap,
75 const char *cmd,
76 int uid,
77 servertype_t servertype)
1815bff5
A
78{
79 server_t *serverp;
80
b51d5b5f 81 debug("adding new server \"%s\" with uid %d\n", cmd, uid);
1815bff5
A
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
b51d5b5f
A
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
1815bff5
A
97 serverp->port = MACH_PORT_NULL;
98 serverp->servertype = servertype;
b51d5b5f
A
99 serverp->activity = 0;
100 serverp->active_services = 0;
1815bff5
A
101 strncpy(serverp->cmd, cmd, sizeof serverp->cmd);
102 LAST_ELEMENT(serverp->cmd) = '\0';
103 }
104 return serverp;
105}
b51d5b5f 106
1815bff5
A
107service_t *
108new_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{
1815bff5 116 service_t *servicep;
1815bff5
A
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';
b51d5b5f 130 servicep->servicetype = servicetype;
1815bff5 131 servicep->bootstrap = bootstrap;
1815bff5 132 servicep->port = service_port;
b51d5b5f
A
133 servicep->server = serverp;
134 servicep->isActive = isActive;
1815bff5
A
135 }
136 return servicep;
137}
138
139bootstrap_info_t *
140new_bootstrap(
141 bootstrap_info_t *parent,
142 mach_port_t bootstrap_port,
143 mach_port_t requestor_port)
144{
1815bff5 145 bootstrap_info_t *bootstrap;
1815bff5
A
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;
1815bff5 157
b51d5b5f
A
158 bootstrap->ref_count = 1;
159 bootstrap->parent = parent;
160 parent->ref_count++;
1815bff5
A
161 }
162 return bootstrap;
163}
164
165bootstrap_info_t *
166lookup_bootstrap_by_port(mach_port_t port)
167{
168 bootstrap_info_t *bootstrap;
b51d5b5f
A
169 bootstrap_info_t *first;
170 server_t *serverp;
1815bff5 171
b51d5b5f
A
172 bootstrap = first = FIRST(bootstraps);
173 do {
1815bff5
A
174 if (bootstrap->bootstrap_port == port)
175 return bootstrap;
b51d5b5f
A
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;
1815bff5 185 }
b51d5b5f 186 return NULL;
1815bff5
A
187}
188
189bootstrap_info_t *
b51d5b5f 190lookup_bootstrap_by_req_port(mach_port_t port)
1815bff5
A
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
205service_t *
206lookup_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
227void
228unlink_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
237void
238delete_service(service_t *servicep)
239{
240 unlink_service(servicep);
b51d5b5f
A
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 }
1815bff5
A
259 free(servicep);
260 nservices -= 1;
261}
262
263void
b51d5b5f 264delete_bootstrap_services(bootstrap_info_t *bootstrap)
1815bff5 265{
b51d5b5f 266 server_t *serverp;
1815bff5
A
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;
b51d5b5f
A
277
278 if (!servicep->isActive || !servicep->server) {
1815bff5 279 delete_service(servicep);
b51d5b5f 280 continue;
1815bff5 281 }
b51d5b5f
A
282
283 serverp = servicep->server;
284 delete_service(servicep);
285 serverp->active_services--;
286 if (!active_server(serverp))
287 delete_server(serverp);
1815bff5
A
288 }
289}
290
291service_t *
292lookup_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
b51d5b5f
A
306service_t *
307lookup_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
1815bff5
A
321server_t *
322lookup_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
1815bff5
A
336server_t *
337lookup_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
b51d5b5f
A
351void
352delete_server(server_t *serverp)
1815bff5 353{
b51d5b5f
A
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)
1815bff5 366 {
b51d5b5f
A
367 next = NEXT(servicep);
368 if (serverp == servicep->server)
369 delete_service(servicep);
1815bff5 370 }
b51d5b5f
A
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
383void
384deactivate_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
468void
469deallocate_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);
1815bff5
A
480}
481
482void *
483ckmalloc(unsigned nbytes)
484{
485 void *cp;
486
487 if ((cp = malloc(nbytes)) == NULL)
488 fatal("Out of memory");
489 return cp;
490}
491
492