Annotation of kernel/kernserv/kern_notify.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.