]>
Commit | Line | Data |
---|---|---|
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 | */ | |
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 */ | |
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 | ||
62 | void | |
63 | init_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 | ||
72 | server_t * | |
73 | new_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 |
107 | service_t * |
108 | new_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 | ||
139 | bootstrap_info_t * | |
140 | new_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 | ||
165 | bootstrap_info_t * | |
166 | lookup_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 | ||
189 | bootstrap_info_t * | |
b51d5b5f | 190 | lookup_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 | ||
205 | service_t * | |
206 | lookup_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 | ||
227 | void | |
228 | unlink_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 | ||
237 | void | |
238 | delete_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 | ||
263 | void | |
b51d5b5f | 264 | delete_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 | ||
291 | service_t * | |
292 | lookup_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 |
306 | service_t * |
307 | lookup_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 |
321 | server_t * |
322 | lookup_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 |
336 | server_t * |
337 | lookup_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 |
351 | void |
352 | delete_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 | ||
383 | void | |
384 | deactivate_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 | ||
468 | void | |
469 | deallocate_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 | ||
482 | void * | |
483 | ckmalloc(unsigned nbytes) | |
484 | { | |
485 | void *cp; | |
486 | ||
487 | if ((cp = malloc(nbytes)) == NULL) | |
488 | fatal("Out of memory"); | |
489 | return cp; | |
490 | } | |
491 | ||
492 |