2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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,
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.
23 * @APPLE_LICENSE_HEADER_END@
26 * bootstrap -- fundamental service initiator and port server
27 * Mike DeMoney, NeXT, Inc.
28 * Copyright, 1990. All rights reserved.
30 * lists.c -- implementation of list handling routines
33 #import <mach/boolean.h>
34 #import <mach/mach_error.h>
39 #import "bootstrap_internal.h"
46 bootstrap_info_t bootstraps
; /* head of list of all bootstrap ports */
47 server_t servers
; /* head of list of all servers */
48 service_t services
; /* head of list of all services */
49 unsigned nservices
; /* number of services in list */
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])
66 bootstraps
.ref_count
= 2; /* make sure we never deallocate this one */
67 bootstraps
.next
= bootstraps
.prev
= &bootstraps
;
68 bootstraps
.parent
= &bootstraps
;
69 servers
.next
= servers
.prev
= &servers
;
70 services
.next
= services
.prev
= &services
;
76 bootstrap_info_t
*bootstrap
,
79 servertype_t servertype
)
83 debug("adding new server \"%s\" with uid %d\n", cmd
, uid
);
84 serverp
= NEW(server_t
, 1);
85 if (serverp
!= NULL
) {
86 /* Doubly linked list */
87 servers
.prev
->next
= serverp
;
88 serverp
->prev
= servers
.prev
;
89 serverp
->next
= &servers
;
90 servers
.prev
= serverp
;
92 bootstrap
->ref_count
++;
93 serverp
->bootstrap
= bootstrap
;
95 serverp
->pid
= NO_PID
;
96 serverp
->task_port
= MACH_PORT_NULL
;
99 serverp
->port
= MACH_PORT_NULL
;
100 serverp
->servertype
= servertype
;
101 serverp
->activity
= 0;
102 serverp
->active_services
= 0;
103 strncpy(serverp
->cmd
, cmd
, sizeof serverp
->cmd
);
104 LAST_ELEMENT(serverp
->cmd
) = '\0';
111 bootstrap_info_t
*bootstrap
,
113 mach_port_t service_port
,
115 servicetype_t servicetype
,
120 servicep
= NEW(service_t
, 1);
121 if (servicep
!= NULL
) {
122 /* Doubly linked list */
123 services
.prev
->next
= servicep
;
124 servicep
->prev
= services
.prev
;
125 servicep
->next
= &services
;
126 services
.prev
= servicep
;
130 strncpy(servicep
->name
, name
, sizeof servicep
->name
);
131 LAST_ELEMENT(servicep
->name
) = '\0';
132 servicep
->servicetype
= servicetype
;
133 servicep
->bootstrap
= bootstrap
;
134 servicep
->port
= service_port
;
135 servicep
->server
= serverp
;
136 servicep
->isActive
= isActive
;
143 bootstrap_info_t
*parent
,
144 mach_port_t bootstrap_port
,
145 mach_port_t requestor_port
)
147 bootstrap_info_t
*bootstrap
;
149 bootstrap
= NEW(bootstrap_info_t
, 1);
150 if (bootstrap
!= NULL
) {
151 /* Doubly linked list */
152 bootstraps
.prev
->next
= bootstrap
;
153 bootstrap
->prev
= bootstraps
.prev
;
154 bootstrap
->next
= &bootstraps
;
155 bootstraps
.prev
= bootstrap
;
157 bootstrap
->bootstrap_port
= bootstrap_port
;
158 bootstrap
->requestor_port
= requestor_port
;
160 bootstrap
->ref_count
= 1;
161 bootstrap
->parent
= parent
;
168 lookup_bootstrap_by_port(mach_port_t port
)
170 bootstrap_info_t
*bootstrap
;
171 bootstrap_info_t
*first
;
174 bootstrap
= first
= FIRST(bootstraps
);
176 if (bootstrap
->bootstrap_port
== port
)
178 bootstrap
= NEXT(bootstrap
);
179 } while (bootstrap
!= first
);
181 for ( serverp
= FIRST(servers
)
182 ; !IS_END(serverp
, servers
)
183 ; serverp
= NEXT(serverp
))
185 if (port
== serverp
->port
)
186 return serverp
->bootstrap
;
192 lookup_bootstrap_by_req_port(mach_port_t port
)
194 bootstrap_info_t
*bootstrap
;
196 for ( bootstrap
= FIRST(bootstraps
)
197 ; !IS_END(bootstrap
, bootstraps
)
198 ; bootstrap
= NEXT(bootstrap
))
200 if (bootstrap
->requestor_port
== port
)
208 lookup_service_by_name(bootstrap_info_t
*bootstrap
, name_t name
)
214 for ( servicep
= FIRST(services
)
215 ; !IS_END(servicep
, services
)
216 ; servicep
= NEXT(servicep
))
218 if (!STREQ(name
, servicep
->name
))
220 if (bootstrap
&& servicep
->bootstrap
!= bootstrap
)
224 } while (bootstrap
!= &bootstraps
&&
225 (bootstrap
= bootstrap
->parent
));
230 unlink_service(service_t
*servicep
)
232 ASSERT(servicep
->prev
->next
== servicep
);
233 ASSERT(servicep
->next
->prev
== servicep
);
234 servicep
->prev
->next
= servicep
->next
;
235 servicep
->next
->prev
= servicep
->prev
;
236 servicep
->prev
= servicep
->next
= servicep
; // idempotent
240 delete_service(service_t
*servicep
)
242 unlink_service(servicep
);
243 switch (servicep
->servicetype
) {
245 info("Registered service %s deleted", servicep
->name
);
246 mach_port_deallocate(mach_task_self(), servicep
->port
);
249 info("Declared service %s now unavailable", servicep
->name
);
250 mach_port_deallocate(mach_task_self(), servicep
->port
);
251 mach_port_mod_refs(mach_task_self(), servicep
->port
,
252 MACH_PORT_RIGHT_RECEIVE
, -1);
255 error("unknown service type %d\n", servicep
->servicetype
);
263 delete_bootstrap_services(bootstrap_info_t
*bootstrap
)
269 for ( servicep
= FIRST(services
)
270 ; !IS_END(servicep
, services
)
273 next
= NEXT(servicep
);
274 if (bootstrap
!= servicep
->bootstrap
)
277 if (!servicep
->isActive
|| !servicep
->server
) {
278 delete_service(servicep
);
282 serverp
= servicep
->server
;
283 delete_service(servicep
);
284 serverp
->active_services
--;
285 if (!active_server(serverp
))
286 delete_server(serverp
);
291 lookup_service_by_port(mach_port_t port
)
295 for ( servicep
= FIRST(services
)
296 ; !IS_END(servicep
, services
)
297 ; servicep
= NEXT(servicep
))
299 if (port
== servicep
->port
)
306 lookup_service_by_server(server_t
*serverp
)
310 for ( servicep
= FIRST(services
)
311 ; !IS_END(servicep
, services
)
312 ; servicep
= NEXT(servicep
))
314 if (serverp
== servicep
->server
)
321 lookup_server_by_task_port(mach_port_t port
)
325 for ( serverp
= FIRST(servers
)
326 ; !IS_END(serverp
, servers
)
327 ; serverp
= NEXT(serverp
))
329 if (port
== serverp
->task_port
)
336 lookup_server_by_port(mach_port_t port
)
340 for ( serverp
= FIRST(servers
)
341 ; !IS_END(serverp
, servers
)
342 ; serverp
= NEXT(serverp
))
344 if (port
== serverp
->port
)
351 delete_server(server_t
*serverp
)
356 info("Deleting server %s", serverp
->cmd
);
357 ASSERT(serverp
->prev
->next
== serverp
);
358 ASSERT(serverp
->next
->prev
== serverp
);
359 serverp
->prev
->next
= serverp
->next
;
360 serverp
->next
->prev
= serverp
->prev
;
362 for ( servicep
= FIRST(services
)
363 ; !IS_END(servicep
, services
)
366 next
= NEXT(servicep
);
367 if (serverp
== servicep
->server
)
368 delete_service(servicep
);
371 deallocate_bootstrap(serverp
->bootstrap
);
374 mach_port_mod_refs(mach_task_self(), serverp
->port
,
375 MACH_PORT_RIGHT_RECEIVE
, -1);
381 deactivate_bootstrap(bootstrap_info_t
*bootstrap
)
383 bootstrap_info_t
*deactivating_bootstraps
;
384 bootstrap_info_t
*query_bootstrap
;
385 bootstrap_info_t
*next_limit
;
386 bootstrap_info_t
*limit
;
389 * we need to recursively deactivate the whole subset tree below
390 * this point. But we don't want to do real recursion because
391 * we don't have a limit on the depth. So, build up a chain of
392 * active bootstraps anywhere underneath this one.
394 deactivating_bootstraps
= bootstrap
;
395 bootstrap
->deactivate
= NULL
;
396 for (next_limit
= deactivating_bootstraps
, limit
= NULL
397 ; deactivating_bootstraps
!= limit
398 ; limit
= next_limit
, next_limit
= deactivating_bootstraps
)
400 for (bootstrap
= deactivating_bootstraps
402 ; bootstrap
= bootstrap
->deactivate
)
404 for ( query_bootstrap
= FIRST(bootstraps
)
405 ; !IS_END(query_bootstrap
, bootstraps
)
406 ; query_bootstrap
= NEXT(query_bootstrap
))
408 if (query_bootstrap
->parent
== bootstrap
&&
409 query_bootstrap
->requestor_port
!= MACH_PORT_NULL
) {
410 mach_port_deallocate(
412 query_bootstrap
->requestor_port
);
413 query_bootstrap
->requestor_port
= MACH_PORT_NULL
;
414 query_bootstrap
->deactivate
= deactivating_bootstraps
;
415 deactivating_bootstraps
= query_bootstrap
;
422 * The list is ordered with the furthest away progeny being
423 * at the front, and concluding with the one we started with.
424 * This allows us to safely deactivate and remove the reference
425 * each holds on their parent without fear of the chain getting
426 * corrupted (because each active parent holds a reference on
427 * itself and that doesn't get removed until we reach its spot
431 bootstrap
= deactivating_bootstraps
;
432 deactivating_bootstraps
= bootstrap
->deactivate
;
434 info("deactivating bootstrap %x", bootstrap
->bootstrap_port
);
436 delete_bootstrap_services(bootstrap
);
438 mach_port_deallocate(mach_task_self(), bootstrap
->bootstrap_port
);
441 mach_port_t previous
;
442 mach_port_request_notification(
444 bootstrap
->bootstrap_port
,
445 MACH_NOTIFY_NO_SENDERS
,
447 bootstrap
->bootstrap_port
,
448 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
451 } while (deactivating_bootstraps
!= NULL
);
455 deallocate_bootstrap(bootstrap_info_t
*bootstrap
)
457 ASSERT(bootstrap
->prev
->next
== bootstrap
);
458 ASSERT(bootstrap
->next
->prev
== bootstrap
);
459 if (--bootstrap
->ref_count
> 0)
462 bootstrap
->prev
->next
= bootstrap
->next
;
463 bootstrap
->next
->prev
= bootstrap
->prev
;
464 deallocate_bootstrap(bootstrap
->parent
);
469 ckmalloc(unsigned nbytes
)
473 if ((cp
= malloc(nbytes
)) == NULL
)
474 fatal("Out of memory");