2 * Copyright (c) 1999-2003 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 bootstraps
.parent
= &bootstraps
;
68 servers
.next
= servers
.prev
= &servers
;
69 services
.next
= services
.prev
= &services
;
75 bootstrap_info_t
*bootstrap
,
78 servertype_t servertype
)
82 debug("adding new server \"%s\" with uid %d\n", cmd
, uid
);
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
;
91 bootstrap
->ref_count
++;
92 serverp
->bootstrap
= bootstrap
;
94 serverp
->pid
= NO_PID
;
95 serverp
->task_port
= MACH_PORT_NULL
;
98 serverp
->port
= MACH_PORT_NULL
;
99 serverp
->servertype
= servertype
;
100 serverp
->activity
= 0;
101 serverp
->active_services
= 0;
102 strncpy(serverp
->cmd
, cmd
, sizeof serverp
->cmd
);
103 LAST_ELEMENT(serverp
->cmd
) = '\0';
110 bootstrap_info_t
*bootstrap
,
112 mach_port_t service_port
,
114 servicetype_t servicetype
,
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
;
129 strncpy(servicep
->name
, name
, sizeof servicep
->name
);
130 LAST_ELEMENT(servicep
->name
) = '\0';
131 servicep
->servicetype
= servicetype
;
132 servicep
->bootstrap
= bootstrap
;
133 servicep
->port
= service_port
;
134 servicep
->server
= serverp
;
135 servicep
->isActive
= isActive
;
142 bootstrap_info_t
*parent
,
143 mach_port_t bootstrap_port
,
144 mach_port_t requestor_port
)
146 bootstrap_info_t
*bootstrap
;
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
;
156 bootstrap
->bootstrap_port
= bootstrap_port
;
157 bootstrap
->requestor_port
= requestor_port
;
159 bootstrap
->ref_count
= 1;
160 bootstrap
->parent
= parent
;
167 lookup_bootstrap_by_port(mach_port_t port
)
169 bootstrap_info_t
*bootstrap
;
170 bootstrap_info_t
*first
;
173 bootstrap
= first
= FIRST(bootstraps
);
175 if (bootstrap
->bootstrap_port
== port
)
177 bootstrap
= NEXT(bootstrap
);
178 } while (bootstrap
!= first
);
180 for ( serverp
= FIRST(servers
)
181 ; !IS_END(serverp
, servers
)
182 ; serverp
= NEXT(serverp
))
184 if (port
== serverp
->port
)
185 return serverp
->bootstrap
;
191 lookup_bootstrap_by_req_port(mach_port_t port
)
193 bootstrap_info_t
*bootstrap
;
195 for ( bootstrap
= FIRST(bootstraps
)
196 ; !IS_END(bootstrap
, bootstraps
)
197 ; bootstrap
= NEXT(bootstrap
))
199 if (bootstrap
->requestor_port
== port
)
207 lookup_service_by_name(bootstrap_info_t
*bootstrap
, name_t name
)
213 for ( servicep
= FIRST(services
)
214 ; !IS_END(servicep
, services
)
215 ; servicep
= NEXT(servicep
))
217 if (!STREQ(name
, servicep
->name
))
219 if (bootstrap
&& servicep
->bootstrap
!= bootstrap
)
223 } while (bootstrap
!= &bootstraps
&&
224 (bootstrap
= bootstrap
->parent
));
229 unlink_service(service_t
*servicep
)
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
239 delete_service(service_t
*servicep
)
241 unlink_service(servicep
);
242 switch (servicep
->servicetype
) {
244 info("Registered service %s deleted", servicep
->name
);
245 mach_port_deallocate(mach_task_self(), servicep
->port
);
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);
254 error("Self service %s now unavailable", servicep
->name
);
257 error("unknown service type %d\n", servicep
->servicetype
);
265 delete_bootstrap_services(bootstrap_info_t
*bootstrap
)
271 for ( servicep
= FIRST(services
)
272 ; !IS_END(servicep
, services
)
275 next
= NEXT(servicep
);
276 if (bootstrap
!= servicep
->bootstrap
)
279 if (!servicep
->isActive
|| !servicep
->server
) {
280 delete_service(servicep
);
284 serverp
= servicep
->server
;
285 delete_service(servicep
);
286 serverp
->active_services
--;
287 if (!active_server(serverp
))
288 delete_server(serverp
);
293 lookup_service_by_port(mach_port_t port
)
297 for ( servicep
= FIRST(services
)
298 ; !IS_END(servicep
, services
)
299 ; servicep
= NEXT(servicep
))
301 if (port
== servicep
->port
)
308 lookup_service_by_server(server_t
*serverp
)
312 for ( servicep
= FIRST(services
)
313 ; !IS_END(servicep
, services
)
314 ; servicep
= NEXT(servicep
))
316 if (serverp
== servicep
->server
)
323 lookup_server_by_task_port(mach_port_t port
)
327 for ( serverp
= FIRST(servers
)
328 ; !IS_END(serverp
, servers
)
329 ; serverp
= NEXT(serverp
))
331 if (port
== serverp
->task_port
)
338 lookup_server_by_port(mach_port_t port
)
342 for ( serverp
= FIRST(servers
)
343 ; !IS_END(serverp
, servers
)
344 ; serverp
= NEXT(serverp
))
346 if (port
== serverp
->port
)
353 delete_server(server_t
*serverp
)
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
;
364 for ( servicep
= FIRST(services
)
365 ; !IS_END(servicep
, services
)
368 next
= NEXT(servicep
);
369 if (serverp
== servicep
->server
)
370 delete_service(servicep
);
373 deallocate_bootstrap(serverp
->bootstrap
);
376 mach_port_mod_refs(mach_task_self(), serverp
->port
,
377 MACH_PORT_RIGHT_RECEIVE
, -1);
383 deactivate_bootstrap(bootstrap_info_t
*bootstrap
)
385 bootstrap_info_t
*deactivating_bootstraps
;
386 bootstrap_info_t
*query_bootstrap
;
387 bootstrap_info_t
*next_limit
;
388 bootstrap_info_t
*limit
;
391 * we need to recursively deactivate the whole subset tree below
392 * this point. But we don't want to do real recursion because
393 * we don't have a limit on the depth. So, build up a chain of
394 * active bootstraps anywhere underneath this one.
396 deactivating_bootstraps
= bootstrap
;
397 bootstrap
->deactivate
= NULL
;
398 for (next_limit
= deactivating_bootstraps
, limit
= NULL
399 ; deactivating_bootstraps
!= limit
400 ; limit
= next_limit
, next_limit
= deactivating_bootstraps
)
402 for (bootstrap
= deactivating_bootstraps
404 ; bootstrap
= bootstrap
->deactivate
)
406 for ( query_bootstrap
= FIRST(bootstraps
)
407 ; !IS_END(query_bootstrap
, bootstraps
)
408 ; query_bootstrap
= NEXT(query_bootstrap
))
410 if (query_bootstrap
->parent
== bootstrap
&&
411 query_bootstrap
->requestor_port
!= MACH_PORT_NULL
) {
412 mach_port_deallocate(
414 query_bootstrap
->requestor_port
);
415 query_bootstrap
->requestor_port
= MACH_PORT_NULL
;
416 query_bootstrap
->deactivate
= deactivating_bootstraps
;
417 deactivating_bootstraps
= query_bootstrap
;
424 * The list is ordered with the furthest away progeny being
425 * at the front, and concluding with the one we started with.
426 * This allows us to safely deactivate and remove the reference
427 * each holds on their parent without fear of the chain getting
428 * corrupted (because each active parent holds a reference on
429 * itself and that doesn't get removed until we reach its spot
433 bootstrap
= deactivating_bootstraps
;
434 deactivating_bootstraps
= bootstrap
->deactivate
;
436 info("deactivating bootstrap %x", bootstrap
->bootstrap_port
);
438 delete_bootstrap_services(bootstrap
);
440 mach_port_deallocate(mach_task_self(), bootstrap
->bootstrap_port
);
443 mach_port_t previous
;
444 mach_port_request_notification(
446 bootstrap
->bootstrap_port
,
447 MACH_NOTIFY_NO_SENDERS
,
449 bootstrap
->bootstrap_port
,
450 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
453 } while (deactivating_bootstraps
!= NULL
);
457 deallocate_bootstrap(bootstrap_info_t
*bootstrap
)
459 ASSERT(bootstrap
->prev
->next
== bootstrap
);
460 ASSERT(bootstrap
->next
->prev
== bootstrap
);
461 if (--bootstrap
->ref_count
> 0)
464 bootstrap
->prev
->next
= bootstrap
->next
;
465 bootstrap
->next
->prev
= bootstrap
->prev
;
466 deallocate_bootstrap(bootstrap
->parent
);
471 ckmalloc(unsigned nbytes
)
475 if ((cp
= malloc(nbytes
)) == NULL
)
476 fatal("Out of memory");