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