2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
25 * bootstrap -- fundamental service initiator and port server
26 * Mike DeMoney, NeXT, Inc.
27 * Copyright, 1990. All rights reserved.
29 * lists.c -- implementation of list handling routines
32 #import <mach/boolean.h>
33 #import <mach/mach_error.h>
38 #import "bootstrap_internal.h"
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 */
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])
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
;
74 bootstrap_info_t
*bootstrap
,
77 servertype_t servertype
)
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
;
90 bootstrap
->ref_count
++;
91 serverp
->bootstrap
= bootstrap
;
93 serverp
->pid
= NO_PID
;
94 serverp
->task_port
= MACH_PORT_NULL
;
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';
109 bootstrap_info_t
*bootstrap
,
111 mach_port_t service_port
,
113 servicetype_t servicetype
,
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
;
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
;
141 bootstrap_info_t
*parent
,
142 mach_port_t bootstrap_port
,
143 mach_port_t requestor_port
)
145 bootstrap_info_t
*bootstrap
;
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
;
155 bootstrap
->bootstrap_port
= bootstrap_port
;
156 bootstrap
->requestor_port
= requestor_port
;
158 bootstrap
->ref_count
= 1;
159 bootstrap
->parent
= parent
;
166 lookup_bootstrap_by_port(mach_port_t port
)
168 bootstrap_info_t
*bootstrap
;
169 bootstrap_info_t
*first
;
172 bootstrap
= first
= FIRST(bootstraps
);
174 if (bootstrap
->bootstrap_port
== port
)
176 bootstrap
= NEXT(bootstrap
);
177 } while (bootstrap
!= first
);
179 for ( serverp
= FIRST(servers
)
180 ; !IS_END(serverp
, servers
)
181 ; serverp
= NEXT(serverp
))
183 if (port
== serverp
->port
)
184 return serverp
->bootstrap
;
190 lookup_bootstrap_by_req_port(mach_port_t port
)
192 bootstrap_info_t
*bootstrap
;
194 for ( bootstrap
= FIRST(bootstraps
)
195 ; !IS_END(bootstrap
, bootstraps
)
196 ; bootstrap
= NEXT(bootstrap
))
198 if (bootstrap
->requestor_port
== port
)
206 lookup_service_by_name(bootstrap_info_t
*bootstrap
, name_t name
)
211 for ( servicep
= FIRST(services
)
212 ; !IS_END(servicep
, services
)
213 ; servicep
= NEXT(servicep
))
215 if (!STREQ(name
, servicep
->name
))
217 if (bootstrap
&& servicep
->bootstrap
!= bootstrap
)
221 bootstrap
= bootstrap
->parent
;
228 unlink_service(service_t
*servicep
)
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
238 delete_service(service_t
*servicep
)
240 unlink_service(servicep
);
241 switch (servicep
->servicetype
) {
243 info("Registered service %s deleted", servicep
->name
);
244 mach_port_deallocate(mach_task_self(), servicep
->port
);
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);
253 error("Self service %s now unavailable", servicep
->name
);
256 error("unknown service type %d\n", servicep
->servicetype
);
264 delete_bootstrap_services(bootstrap_info_t
*bootstrap
)
270 for ( servicep
= FIRST(services
)
271 ; !IS_END(servicep
, services
)
274 next
= NEXT(servicep
);
275 if (bootstrap
!= servicep
->bootstrap
)
278 if (!servicep
->isActive
|| !servicep
->server
) {
279 delete_service(servicep
);
283 serverp
= servicep
->server
;
284 delete_service(servicep
);
285 serverp
->active_services
--;
286 if (!active_server(serverp
))
287 delete_server(serverp
);
292 lookup_service_by_port(mach_port_t port
)
296 for ( servicep
= FIRST(services
)
297 ; !IS_END(servicep
, services
)
298 ; servicep
= NEXT(servicep
))
300 if (port
== servicep
->port
)
307 lookup_service_by_server(server_t
*serverp
)
311 for ( servicep
= FIRST(services
)
312 ; !IS_END(servicep
, services
)
313 ; servicep
= NEXT(servicep
))
315 if (serverp
== servicep
->server
)
322 lookup_server_by_task_port(mach_port_t port
)
326 for ( serverp
= FIRST(servers
)
327 ; !IS_END(serverp
, servers
)
328 ; serverp
= NEXT(serverp
))
330 if (port
== serverp
->task_port
)
337 lookup_server_by_port(mach_port_t port
)
341 for ( serverp
= FIRST(servers
)
342 ; !IS_END(serverp
, servers
)
343 ; serverp
= NEXT(serverp
))
345 if (port
== serverp
->port
)
352 delete_server(server_t
*serverp
)
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
;
363 for ( servicep
= FIRST(services
)
364 ; !IS_END(servicep
, services
)
367 next
= NEXT(servicep
);
368 if (serverp
== servicep
->server
)
369 delete_service(servicep
);
372 deallocate_bootstrap(serverp
->bootstrap
);
374 #ifndef DELAYED_BOOTSTRAP_DESTROY
376 mach_port_mod_refs(mach_task_self(), serverp
->port
,
377 MACH_PORT_RIGHT_RECEIVE
, -1);
384 deactivate_bootstrap(bootstrap_info_t
*bootstrap
)
386 bootstrap_info_t
*deactivating_bootstraps
;
387 bootstrap_info_t
*query_bootstrap
;
388 bootstrap_info_t
*next_limit
;
389 bootstrap_info_t
*limit
;
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.
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
)
403 for (bootstrap
= deactivating_bootstraps
405 ; bootstrap
= bootstrap
->deactivate
)
407 for ( query_bootstrap
= FIRST(bootstraps
)
408 ; !IS_END(query_bootstrap
, bootstraps
)
409 ; query_bootstrap
= NEXT(query_bootstrap
))
411 if (query_bootstrap
->parent
== bootstrap
&&
412 query_bootstrap
->requestor_port
!= MACH_PORT_NULL
) {
413 mach_port_deallocate(
415 query_bootstrap
->requestor_port
);
416 query_bootstrap
->requestor_port
= MACH_PORT_NULL
;
417 query_bootstrap
->deactivate
= deactivating_bootstraps
;
418 deactivating_bootstraps
= query_bootstrap
;
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
434 bootstrap
= deactivating_bootstraps
;
435 deactivating_bootstraps
= bootstrap
->deactivate
;
437 info("deactivating bootstrap %x", bootstrap
->bootstrap_port
);
439 delete_bootstrap_services(bootstrap
);
441 mach_port_deallocate(mach_task_self(), bootstrap
->bootstrap_port
);
443 #ifdef DELAYED_BOOTSTRAP_DESTROY
445 mach_port_t previous
;
446 mach_port_request_notification(
448 bootstrap
->bootstrap_port
,
449 MACH_NOTIFY_NO_SENDERS
,
451 bootstrap
->bootstrap_port
,
452 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
458 bootstrap
->bootstrap_port
,
459 MACH_PORT_RIGHT_RECEIVE
,
461 bootstrap
->bootstrap_port
= MACH_PORT_NULL
;
462 deallocate_bootstrap(bootstrap
);
465 } while (deactivating_bootstraps
!= NULL
);
469 deallocate_bootstrap(bootstrap_info_t
*bootstrap
)
471 ASSERT(bootstrap
->prev
->next
== bootstrap
);
472 ASSERT(bootstrap
->next
->prev
== bootstrap
);
473 if (--bootstrap
->ref_count
> 0)
476 bootstrap
->prev
->next
= bootstrap
->next
;
477 bootstrap
->next
->prev
= bootstrap
->prev
;
478 deallocate_bootstrap(bootstrap
->parent
);
483 ckmalloc(unsigned nbytes
)
487 if ((cp
= malloc(nbytes
)) == NULL
)
488 fatal("Out of memory");