|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
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.1 (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: /* @(#)ipc_notify.c 2.0 05/11/90 (c) 1990 NeXT */
26:
27: /*
28: * ipc_notify.c - port death notification server
29: *
30: * HISTORY
31: * 05-11-90 Doug Mitchell at NeXT
32: * Created.
33: */
34:
35: #import <mach/mach_types.h>
36:
37: #import <kern/queue.h>
38: #import <kern/kern_port.h>
39: #import <mach/notify.h>
40: #import <mach/task_special_ports.h>
41: #import <kernserv/kern_notify.h>
42:
43: /* #define PN_DEBUG 1 /* */
44:
45: #ifdef PN_DEBUG
46: #define pn_debug(x) printf x
47: #else PN_DEBUG
48: #define pn_debug(x)
49: #endif PN_DEBUG
50:
51: /*
52: * This module provides a means for kernel threads to receive port death
53: * notification. This module is implemented as a task separate from the kernel;
54: * kernel threads register ports in which they are interested via
55: * port_request_notification(). The notification server receives notification
56: * in the normal fashion and forwards the notification on to a port registered
57: * in the port_request_notification() call.
58: */
59:
60: /*
61: * struct used to maintain list of registered ports.
62: */
63: struct pn_register_ent {
64: queue_chain_t link;
65: port_t rights_port;
66: port_t notify_port;
67: int rights_port_rep;
68: };
69:
70: typedef struct pn_register_ent *pn_register_ent_t;
71:
72: /*
73: * local functions.
74: */
75: static void pn_panic(kern_return_t krtn, char *err_string);
76: static void pn_register(port_register_notify_t prn_msg);
77: static void pn_notify(notification_t *nmsg);
78:
79: /*
80: * global variables.
81: */
82: port_t pn_register_port=PORT_NULL; /* requests from kernel threads are
83: * sent here */
84: kern_port_t pn_register_port_k; /* internal version of same */
85: static port_t pn_notify_port; /* port death notifications are sent
86: * here */
87: static kern_port_t pn_notify_port_k;
88: /* internal version of same */
89: static port_set_name_t pnotify_port_set;
90: static queue_head_t pn_reg_q; /* maintains registration info */
91:
92: /*
93: * Message templates.
94: */
95: static struct port_register_notify prn_temp = {
96: { /* prn_header */
97: 0, /* msg_unused */
98: FALSE, /* msg_simple */
99: sizeof(struct port_register_notify),
100: MSG_TYPE_NORMAL, /* msg_type */
101: PORT_NULL,
102: PORT_NULL,
103: PORT_REGISTER_NOTIFY /* msg_id */
104: },
105: { /* prn_p_type */
106: MSG_TYPE_PORT, /* msg_type_name */
107: 8 * sizeof(port_t), /* msg_type_size */
108: 2, /* msg_type_number */
109: TRUE, /* msg_type_inline */
110: FALSE, /* msg_type_longform */
111: FALSE, /* msg_type_deallocate */
112: 0 /* msg_type_unused */
113: },
114: PORT_NULL, /* prn_rights_port */
115: PORT_NULL, /* prn_notify_port */
116: { /* prn_rpr_type */
117: MSG_TYPE_INTEGER_32, /* msg_type_name */
118: 8 * sizeof(int), /* msg_type_size */
119: 1, /* msg_type_number */
120: TRUE, /* msg_type_inline */
121: FALSE, /* msg_type_longform */
122: FALSE, /* msg_type_deallocate */
123: 0 /* msg_type_unused */
124: },
125: 0 /* prn_rp_rep */
126: };
127:
128: /*
129: * Remove a pn_register_ent from the queue and deallocate it.
130: */
131: #define pn_remove(prp) \
132: { \
133: queue_remove(&pn_reg_q, prp, struct pn_register_ent *, link); \
134: kfree(prp, sizeof(*prp)); \
135: }
136:
137: void notify_server_loop() {
138: kern_return_t krtn;
139: msg_header_t *msg;
140: task_t pn_task;
141:
142: current_task()->kernel_vm_space = TRUE;
143: /*
144: * set up ports we'll use.
145: */
146: pn_task = current_task();
147: krtn = port_allocate(pn_task->itk_space, &pn_notify_port);
148: if(krtn)
149: pn_panic(krtn, "port_allocate");
150: /*
151: * task_set_special_port needs a kern_port_t. All other ipc calls
152: * used here work with port_t's.
153: */
154: get_kern_port(pn_task, pn_notify_port, &pn_notify_port_k);
155: krtn = task_set_special_port(pn_task, TASK_NOTIFY_PORT,
156: pn_notify_port_k);
157: if(krtn)
158: pn_panic(krtn, "task_set_special_port");
159: krtn = port_allocate(pn_task->itk_space, &pn_register_port);
160: if(krtn)
161: pn_panic(krtn, "port_allocate");
162: /*
163: * Get internal version of pn_register_port.
164: */
165: get_kern_port(pn_task, pn_register_port, &pn_register_port_k);
166: krtn = port_set_allocate(pn_task->itk_space, &pnotify_port_set);
167: if(krtn)
168: pn_panic(krtn, "port_set_allocate");
169: krtn = port_set_add(pn_task->itk_space, pnotify_port_set, pn_notify_port);
170: if(krtn)
171: pn_panic(krtn, "port_set_add");
172: krtn = port_set_add(pn_task->itk_space, pnotify_port_set, pn_register_port);
173: if(krtn)
174: pn_panic(krtn, "port_set_add");
175: /*
176: * Other initialization.
177: */
178: msg = (msg_header_t *)kalloc(MSG_SIZE_MAX);
179: queue_init(&pn_reg_q);
180:
181: /*
182: * Main loop. Just handle incoming messages.
183: */
184: while(1) {
185: msg->msg_local_port = pnotify_port_set;
186: msg->msg_size = MSG_SIZE_MAX;
187: krtn = msg_receive(msg, MSG_OPTION_NONE, 0);
188: if(krtn) {
189: printf("notify_server_loop: msg_receive error (%d)\n",
190: krtn);
191: continue;
192: }
193: if(msg->msg_local_port == pn_register_port)
194: pn_register((port_register_notify_t)msg);
195: else if(msg->msg_local_port == pn_notify_port)
196: pn_notify((notification_t *)msg);
197: else
198: printf("notify_server_loop: BOGUS msg_local_port\n");
199:
200: }
201: /* NOT REACHED */
202: } /* notify_server_loop() */
203:
204: static void pn_panic(kern_return_t krtn, char *err_string)
205: {
206: printf("notification server: %s: krtn = %d\n", err_string, krtn);
207: panic("notification server");
208:
209: }
210:
211: /*
212: * A kernel thread is registering a port.
213: */
214: static void pn_register(port_register_notify_t prn_msg)
215: {
216: pn_register_ent_t prp;
217:
218: switch(prn_msg->prn_header.msg_id) {
219: case PORT_REGISTER_NOTIFY:
220: pn_debug(("pn_register: registering rights_port\n"));
221: prp = (void *)kalloc(sizeof(*prp));
222: prp->rights_port = (port_t)prn_msg->prn_rights_port;
223: prp->notify_port = (port_t)prn_msg->prn_notify_port;
224: prp->rights_port_rep = prn_msg->prn_rp_rep;
225: queue_enter(&pn_reg_q, prp, struct pn_register_ent *, link);
226: break;
227: default:
228: /*
229: * We only know how to do one thing now.
230: */
231: printf("notify server: bogus msg_id on pn_register_port "
232: "(%d)\n", prn_msg->prn_header.msg_id);
233: break;
234: }
235: }
236:
237: /*
238: * A port has died. This could be one of three kinds of ports:
239: *
240: * 1) a port registered previously as a prn_rights_port. Forward this
241: * message to the appropriate prn_notify_port. This is the "normal"
242: * function of this task.
243: * 2) a port registered previously as a prn_notify_port. A kernel thread
244: * has died.
245: * 3) A port we know nothing about.
246: *
247: * In the first two cases, we remove a pn_register_ent entry from pn_reg_q.
248: */
249: static void pn_notify(notification_t *nmsg)
250: {
251: pn_register_ent_t prp, next_prp;
252: kern_return_t krtn;
253: int port_found = 0;
254:
255: if(nmsg->notify_header.msg_id != NOTIFY_PORT_DELETED) {
256: /*
257: * Huh? What's this?!
258: */
259: printf("pn_notify: msg_id = %d, unrecognized\n",
260: nmsg->notify_header.msg_id);
261: return;
262: }
263: prp = (pn_register_ent_t)queue_first(&pn_reg_q);
264: while(!queue_end(&pn_reg_q, (queue_t)prp)) {
265: next_prp = (pn_register_ent_t)prp->link.next;
266: if(nmsg->notify_port == prp->notify_port) {
267: /*
268: * A kernel thread either died or deallocated its
269: * notify port. Forget this entry.
270: */
271: pn_debug(("pn_notify: NOTIFY_PORT DEATH\n"));
272: pn_remove(prp);
273: port_found++;
274: goto next_elt;
275: }
276: else if(nmsg->notify_port == prp->rights_port) {
277: /*
278: * A kernel thread needs to be notified of this. Then
279: * we can forget this pn_register_ent since the
280: * rights_port is dead.
281: */
282: pn_debug(("pn_notify: RIGHTS_PORT DEATH\n"));
283: nmsg->notify_header.msg_remote_port = prp->notify_port;
284: nmsg->notify_header.msg_local_port = PORT_NULL;
285: /*
286: * We don't pass a port_t to the target thread since
287: * this port is already dead. Convert message to one
288: * which passes an int.
289: */
290: nmsg->notify_header.msg_simple = TRUE;
291: nmsg->notify_type.msg_type_name = MSG_TYPE_INTEGER_32;
292: nmsg->notify_type.msg_type_size = 8 * sizeof(int);
293: nmsg->notify_port = (port_t)prp->rights_port_rep;
294:
295: krtn = msg_send(&nmsg->notify_header, SEND_TIMEOUT, 0);
296: if(krtn)
297: printf("pn_notify: msg_send returned "
298: "%d\n", krtn);
299: pn_remove(prp);
300: port_found++;
301: }
302: next_elt:
303: prp = next_prp; /* next in the queue */
304: }
305: if(!port_found)
306: printf("pn_notify: PORT NOT FOUND\n");
307:
308: } /* pn_notify() */
309:
310: /*
311: * Register reg_port for notification on notify_port.
312: */
313: void port_request_notification(kern_port_t reg_port,
314: kern_port_t notify_port)
315: {
316: struct port_register_notify pnmsg;
317: kern_return_t krtn;
318:
319: pnmsg = prn_temp;
320: pnmsg.prn_rights_port = reg_port;
321: pnmsg.prn_notify_port = notify_port;
322: pnmsg.prn_header.msg_local_port = PORT_NULL;
323: pnmsg.prn_header.msg_remote_port = (port_t)pn_register_port_k;
324: /*
325: * Provide a non-translated version of reg_port; this will be
326: * sent to the registering thread upon port death.
327: */
328: pnmsg.prn_rp_rep = (int)reg_port;
329: krtn = msg_send_from_kernel(&pnmsg.prn_header,
330: SEND_TIMEOUT,
331: 0); /* don't block if queue full */
332: if(krtn)
333: printf("port_request_notification: msg_send returned %d\n",
334: krtn);
335: }
336:
337: void pnotify_start()
338: {
339: /*
340: * Start up the notification server.
341: */
342: task_t newtask;
343: thread_t newthread;
344: kern_return_t krtn;
345:
346: (void) task_create(kernel_task, FALSE, &newtask);
347: task_deallocate(newtask);
348: (void) thread_create(newtask, &newthread);
349: thread_deallocate(newthread);
350: thread_start(newthread, notify_server_loop);
351: (void) thread_resume(newthread);
352: pn_debug(("pnotify_start: notification server started\n"));
353: }
354:
355: /*
356: * Convert port_t to kern_port_t.
357: */
358: kern_return_t get_kern_port(task_t task, port_t in_port, kern_port_t *kport)
359: {
360: if(in_port == (port_t)0) {
361: *kport = PORT_NULL;
362: return(KERN_SUCCESS);
363: }
364: if(!object_copyin(task, in_port, MSG_TYPE_PORT, FALSE, kport))
365: return(KERN_INVALID_ARGUMENT);
366: else
367: return(KERN_SUCCESS);
368: }
369:
370: /* end of ipc_notify.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.