|
|
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.