1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/port_impl.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/task.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/project.h> 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate /* 46*7c478bd9Sstevel@tonic-gate * Event Ports can be shared across threads or across processes. 47*7c478bd9Sstevel@tonic-gate * Every thread/process can use an own event port or a group of them 48*7c478bd9Sstevel@tonic-gate * can use a single port. A major request was also to get the ability 49*7c478bd9Sstevel@tonic-gate * to submit user-defined events to a port. The idea of the 50*7c478bd9Sstevel@tonic-gate * user-defined events is to use the event ports for communication between 51*7c478bd9Sstevel@tonic-gate * threads/processes (like message queues). User defined-events are queued 52*7c478bd9Sstevel@tonic-gate * in a port with the same priority as other event types. 53*7c478bd9Sstevel@tonic-gate * 54*7c478bd9Sstevel@tonic-gate * Events are delivered only once. The thread/process which is waiting 55*7c478bd9Sstevel@tonic-gate * for events with the "highest priority" (priority here is related to the 56*7c478bd9Sstevel@tonic-gate * internal strategy to wakeup waiting threads) will retrieve the event, 57*7c478bd9Sstevel@tonic-gate * all other threads/processes will not be notified. There is also 58*7c478bd9Sstevel@tonic-gate * the requirement to have events which should be submitted immediately 59*7c478bd9Sstevel@tonic-gate * to all "waiting" threads. That is the main task of the alert event. 60*7c478bd9Sstevel@tonic-gate * The alert event is submitted by the application to a port. The port 61*7c478bd9Sstevel@tonic-gate * changes from a standard mode to the alert mode. Now all waiting threads 62*7c478bd9Sstevel@tonic-gate * will be awaken immediately and they will return with the alert event. 63*7c478bd9Sstevel@tonic-gate * Threads trying to retrieve events from a port in alert mode will 64*7c478bd9Sstevel@tonic-gate * return immediately with the alert event. 65*7c478bd9Sstevel@tonic-gate * 66*7c478bd9Sstevel@tonic-gate * 67*7c478bd9Sstevel@tonic-gate * An event port is like a kernel queue, which accept events submitted from 68*7c478bd9Sstevel@tonic-gate * user level as well as events submitted from kernel sub-systems. Sub-systems 69*7c478bd9Sstevel@tonic-gate * able to submit events to a port are the so-called "event sources". 70*7c478bd9Sstevel@tonic-gate * Current event sources: 71*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_AIO : events submitted per transaction completion from 72*7c478bd9Sstevel@tonic-gate * POSIX-I/O framework. 73*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_TIMER : events submitted when a timer fires 74*7c478bd9Sstevel@tonic-gate * (see timer_create(3RT)). 75*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_FD : events submitted per file descriptor (see poll(2)). 76*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_ALERT : events submitted from user. This is not really a 77*7c478bd9Sstevel@tonic-gate * single event, this is actually a port mode 78*7c478bd9Sstevel@tonic-gate * (see port_alert(3c)). 79*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_USER : events submitted by applications with 80*7c478bd9Sstevel@tonic-gate * port_send(3c) or port_sendn(3c). 81*7c478bd9Sstevel@tonic-gate * 82*7c478bd9Sstevel@tonic-gate * There is a user API implemented in the libc library as well as a 83*7c478bd9Sstevel@tonic-gate * kernel API implemented in port_subr.c in genunix. 84*7c478bd9Sstevel@tonic-gate * The available user API functions are: 85*7c478bd9Sstevel@tonic-gate * port_create() : create a port as a file descriptor of portfs file system 86*7c478bd9Sstevel@tonic-gate * The standard close(2) function closes a port. 87*7c478bd9Sstevel@tonic-gate * port_associate() : associate a file descriptor with a port to be able to 88*7c478bd9Sstevel@tonic-gate * retrieve events from that file descriptor. 89*7c478bd9Sstevel@tonic-gate * port_dissociate(): remove the association of a file descriptor with a port. 90*7c478bd9Sstevel@tonic-gate * port_alert() : set/unset a port in alert mode 91*7c478bd9Sstevel@tonic-gate * port_send() : send an event of type PORT_SOURCE_USER to a port 92*7c478bd9Sstevel@tonic-gate * port_sendn() : send an event of type PORT_SOURCE_USER to a list of ports 93*7c478bd9Sstevel@tonic-gate * port_get() : retrieve a single event from a port 94*7c478bd9Sstevel@tonic-gate * port_getn() : retrieve a list of events from a port 95*7c478bd9Sstevel@tonic-gate * 96*7c478bd9Sstevel@tonic-gate * The available kernel API functions are: 97*7c478bd9Sstevel@tonic-gate * port_allocate_event(): allocate an event slot/structure of/from a port 98*7c478bd9Sstevel@tonic-gate * port_init_event() : set event data in the event structure 99*7c478bd9Sstevel@tonic-gate * port_send_event() : send event to a port 100*7c478bd9Sstevel@tonic-gate * port_free_event() : deliver allocated slot/structure back to a port 101*7c478bd9Sstevel@tonic-gate * port_associate_ksource(): associate a kernel event source with a port 102*7c478bd9Sstevel@tonic-gate * port_dissociate_ksource(): dissociate a kernel event source from a port 103*7c478bd9Sstevel@tonic-gate * 104*7c478bd9Sstevel@tonic-gate * The libc implementation consists of small functions which pass the 105*7c478bd9Sstevel@tonic-gate * arguments to the kernel using the "portfs" system call. It means, all the 106*7c478bd9Sstevel@tonic-gate * synchronisation work is being done in the kernel. The "portfs" system 107*7c478bd9Sstevel@tonic-gate * call loads the portfs file system into the kernel. 108*7c478bd9Sstevel@tonic-gate * 109*7c478bd9Sstevel@tonic-gate * PORT CREATION 110*7c478bd9Sstevel@tonic-gate * The first function to be used is port_create() which internally creates 111*7c478bd9Sstevel@tonic-gate * a vnode and a portfs node. The portfs node is represented by the port_t 112*7c478bd9Sstevel@tonic-gate * structure, which again includes all the data necessary to control a port. 113*7c478bd9Sstevel@tonic-gate * port_create() returns a file descriptor, which needs to be used in almost 114*7c478bd9Sstevel@tonic-gate * all other event port functions. 115*7c478bd9Sstevel@tonic-gate * The maximum number of ports per system is controlled by the resource 116*7c478bd9Sstevel@tonic-gate * control: project:port-max-ids. 117*7c478bd9Sstevel@tonic-gate * 118*7c478bd9Sstevel@tonic-gate * EVENT GENERATION 119*7c478bd9Sstevel@tonic-gate * The second step is the triggering of events, which could be sent to a port. 120*7c478bd9Sstevel@tonic-gate * Every event source implements an own method to generate events for a port: 121*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_AIO: 122*7c478bd9Sstevel@tonic-gate * The sigevent structure of the standard POSIX-IO functions 123*7c478bd9Sstevel@tonic-gate * was extended by an additional notification type. 124*7c478bd9Sstevel@tonic-gate * Standard notification types: 125*7c478bd9Sstevel@tonic-gate * SIGEV_NONE, SIGEV_SIGNAL and SIGEV_THREAD 126*7c478bd9Sstevel@tonic-gate * Event ports introduced now SIGEV_PORT. 127*7c478bd9Sstevel@tonic-gate * The notification type SIGEV_PORT specifies that a structure 128*7c478bd9Sstevel@tonic-gate * of type port_notify_t has to be attached to the sigev_value. 129*7c478bd9Sstevel@tonic-gate * The port_notify_t structure contains the event port file 130*7c478bd9Sstevel@tonic-gate * descriptor and a user-defined pointer. 131*7c478bd9Sstevel@tonic-gate * Internally the AIO implementation will use the kernel API 132*7c478bd9Sstevel@tonic-gate * functions to allocate an event port slot per transaction (aiocb) 133*7c478bd9Sstevel@tonic-gate * and sent the event to the port as soon as the transaction completes. 134*7c478bd9Sstevel@tonic-gate * All the events submitted per transaction are of type 135*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_AIO. 136*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_TIMER: 137*7c478bd9Sstevel@tonic-gate * The timer_create() function uses the same method as the 138*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_AIO event source. It also uses the sigevent structure 139*7c478bd9Sstevel@tonic-gate * to deliver the port information. 140*7c478bd9Sstevel@tonic-gate * Internally the timer code will allocate a single event slot/struct 141*7c478bd9Sstevel@tonic-gate * per timer and it will send the timer event as soon as the timer 142*7c478bd9Sstevel@tonic-gate * fires. If the timer-fired event is not delivered to the application 143*7c478bd9Sstevel@tonic-gate * before the next period elapsed, then an overrun counter will be 144*7c478bd9Sstevel@tonic-gate * incremented. The timer event source uses a callback function to 145*7c478bd9Sstevel@tonic-gate * detect the delivery of the event to the application. At that time 146*7c478bd9Sstevel@tonic-gate * the timer callback function will update the event overrun counter. 147*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_FD: 148*7c478bd9Sstevel@tonic-gate * This event source uses the port_associate() function to allocate 149*7c478bd9Sstevel@tonic-gate * an event slot/struct from a port. The application defines in the 150*7c478bd9Sstevel@tonic-gate * events argument of port_associate() the type of events which it is 151*7c478bd9Sstevel@tonic-gate * interested on. 152*7c478bd9Sstevel@tonic-gate * The internal pollwakeup() function is used by all the file 153*7c478bd9Sstevel@tonic-gate * systems --which are supporting the VOP_POLL() interface- to notify 154*7c478bd9Sstevel@tonic-gate * the upper layer (poll(2), devpoll(7d) and now event ports) about 155*7c478bd9Sstevel@tonic-gate * the event triggered (see valid events in poll(2)). 156*7c478bd9Sstevel@tonic-gate * The pollwakeup() function forwards the event to the layer registered 157*7c478bd9Sstevel@tonic-gate * to receive the current event. 158*7c478bd9Sstevel@tonic-gate * The port_dissociate() function can be used to free the allocated 159*7c478bd9Sstevel@tonic-gate * event slot from the port. Anyway, file descriptors deliver events 160*7c478bd9Sstevel@tonic-gate * only one time and remain deactivated until the application 161*7c478bd9Sstevel@tonic-gate * reactivates the association of a file descriptor with port_associate(). 162*7c478bd9Sstevel@tonic-gate * If an associated file descriptor is closed then the file descriptor 163*7c478bd9Sstevel@tonic-gate * will be dissociated automatically from the port. 164*7c478bd9Sstevel@tonic-gate * 165*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_ALERT: 166*7c478bd9Sstevel@tonic-gate * This event type is generated when the port was previously set in 167*7c478bd9Sstevel@tonic-gate * alert mode using the port_alert() function. 168*7c478bd9Sstevel@tonic-gate * A single alert event is delivered to every thread which tries to 169*7c478bd9Sstevel@tonic-gate * retrieve events from a port. 170*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_USER: 171*7c478bd9Sstevel@tonic-gate * This type of event is generated from user level using the port_send() 172*7c478bd9Sstevel@tonic-gate * function to send a user event to a port or the port_sendn() function 173*7c478bd9Sstevel@tonic-gate * to send an event to a list of ports. 174*7c478bd9Sstevel@tonic-gate * 175*7c478bd9Sstevel@tonic-gate * EVENT DELIVERY / RETRIEVING EVENTS 176*7c478bd9Sstevel@tonic-gate * Events remain in the port queue until: 177*7c478bd9Sstevel@tonic-gate * - the application uses port_get() or port_getn() to retrieve events, 178*7c478bd9Sstevel@tonic-gate * - the event source cancel the event, 179*7c478bd9Sstevel@tonic-gate * - the event port is closed or 180*7c478bd9Sstevel@tonic-gate * - the process exits. 181*7c478bd9Sstevel@tonic-gate * The maximal number of events in a port queue is the maximal number 182*7c478bd9Sstevel@tonic-gate * of event slots/structures which can be allocated by event sources. 183*7c478bd9Sstevel@tonic-gate * The allocation of event slots/structures is controlled by the resource 184*7c478bd9Sstevel@tonic-gate * control: process.port-max-events. 185*7c478bd9Sstevel@tonic-gate * The port_get() function retrieves a single event and the port_getn() 186*7c478bd9Sstevel@tonic-gate * function retrieves a list of events. 187*7c478bd9Sstevel@tonic-gate * Events are classified as shareable and non-shareable events across processes. 188*7c478bd9Sstevel@tonic-gate * Non-shareable events are invisible for the port_get(n)() functions of 189*7c478bd9Sstevel@tonic-gate * processes other than the owner of the event. 190*7c478bd9Sstevel@tonic-gate * Shareable event types are: 191*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_USER events 192*7c478bd9Sstevel@tonic-gate * This type of event is unconditionally shareable and without 193*7c478bd9Sstevel@tonic-gate * limitations. If the parent process sends a user event and closes 194*7c478bd9Sstevel@tonic-gate * the port afterwards, the event remains in the port and the child 195*7c478bd9Sstevel@tonic-gate * process will still be able to retrieve the user event. 196*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_ALERT events 197*7c478bd9Sstevel@tonic-gate * This type of event is shareable between processes. 198*7c478bd9Sstevel@tonic-gate * Limitation: The alert mode of the port is removed if the owner 199*7c478bd9Sstevel@tonic-gate * (process which set the port in alert mode) of the 200*7c478bd9Sstevel@tonic-gate * alert event closes the port. 201*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_FD events 202*7c478bd9Sstevel@tonic-gate * This type of event is conditional shareable between processes. 203*7c478bd9Sstevel@tonic-gate * After fork(2) all forked file descriptors are shareable between 204*7c478bd9Sstevel@tonic-gate * the processes. The child process is allowed to retrieve events 205*7c478bd9Sstevel@tonic-gate * from the associated file descriptors and it can also re-associate 206*7c478bd9Sstevel@tonic-gate * the fd with the port. 207*7c478bd9Sstevel@tonic-gate * Limitations: The child process is not allowed to dissociate 208*7c478bd9Sstevel@tonic-gate * the file descriptor from the port. Only the 209*7c478bd9Sstevel@tonic-gate * owner (process) of the association is allowed to 210*7c478bd9Sstevel@tonic-gate * dissociate the file descriptor from the port. 211*7c478bd9Sstevel@tonic-gate * If the owner of the association closes the port 212*7c478bd9Sstevel@tonic-gate * the association will be removed. 213*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_AIO events 214*7c478bd9Sstevel@tonic-gate * This type of event is not shareable between processes. 215*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_TIMER events 216*7c478bd9Sstevel@tonic-gate * This type of event is not shareable between processes. 217*7c478bd9Sstevel@tonic-gate * 218*7c478bd9Sstevel@tonic-gate * FORK BEHAVIOUR 219*7c478bd9Sstevel@tonic-gate * On fork(2) the child process inherits all opened file descriptors from 220*7c478bd9Sstevel@tonic-gate * the parent process. This is also valid for port file descriptors. 221*7c478bd9Sstevel@tonic-gate * Associated file descriptors with a port maintain the association across the 222*7c478bd9Sstevel@tonic-gate * fork(2). It means, the child process gets full access to the port and 223*7c478bd9Sstevel@tonic-gate * it can retrieve events from all common associated file descriptors. 224*7c478bd9Sstevel@tonic-gate * Events of file descriptors created and associated with a port after the 225*7c478bd9Sstevel@tonic-gate * fork(2) are non-shareable and can only be retrieved by the same process. 226*7c478bd9Sstevel@tonic-gate * 227*7c478bd9Sstevel@tonic-gate * If the parent or the child process closes an exported port (using fork(2) 228*7c478bd9Sstevel@tonic-gate * or I_SENDFD) all the file descriptors associated with the port by the 229*7c478bd9Sstevel@tonic-gate * process will be dissociated from the port. Events of dissociated file 230*7c478bd9Sstevel@tonic-gate * descriptors as well as all non-shareable events will be discarded. 231*7c478bd9Sstevel@tonic-gate * The other process can continue working with the port as usual. 232*7c478bd9Sstevel@tonic-gate * 233*7c478bd9Sstevel@tonic-gate * CLOSING A PORT 234*7c478bd9Sstevel@tonic-gate * close(2) has to be used to close a port. See FORK BEHAVIOUR for details. 235*7c478bd9Sstevel@tonic-gate * 236*7c478bd9Sstevel@tonic-gate * PORT EVENT STRUCTURES 237*7c478bd9Sstevel@tonic-gate * The global control structure of the event ports framework is port_control_t. 238*7c478bd9Sstevel@tonic-gate * port_control_t keeps track of the number of created ports in the system. 239*7c478bd9Sstevel@tonic-gate * The cache of the port event structures is also located in port_control_t. 240*7c478bd9Sstevel@tonic-gate * 241*7c478bd9Sstevel@tonic-gate * On port_create() the vnode and the portfs node is also created. 242*7c478bd9Sstevel@tonic-gate * The portfs node is represented by the port_t structure. 243*7c478bd9Sstevel@tonic-gate * The port_t structure manages all port specific tasks: 244*7c478bd9Sstevel@tonic-gate * - management of resource control values 245*7c478bd9Sstevel@tonic-gate * - port VOP_POLL interface 246*7c478bd9Sstevel@tonic-gate * - creation time 247*7c478bd9Sstevel@tonic-gate * - uid and gid of the port 248*7c478bd9Sstevel@tonic-gate * 249*7c478bd9Sstevel@tonic-gate * The port_t structure contains the port_queue_t structure. 250*7c478bd9Sstevel@tonic-gate * The port_queue_t structure contains all the data necessary for the 251*7c478bd9Sstevel@tonic-gate * queue management: 252*7c478bd9Sstevel@tonic-gate * - locking 253*7c478bd9Sstevel@tonic-gate * - condition variables 254*7c478bd9Sstevel@tonic-gate * - event counters 255*7c478bd9Sstevel@tonic-gate * - submitted events (represented by port_kevent_t structures) 256*7c478bd9Sstevel@tonic-gate * - threads waiting for event delivery (check portget_t structure) 257*7c478bd9Sstevel@tonic-gate * - PORT_SOURCE_FD cache (managed by the port_fdcache_t structure) 258*7c478bd9Sstevel@tonic-gate * - event source management (managed by the port_source_t structure) 259*7c478bd9Sstevel@tonic-gate * - alert mode management (check port_alert_t structure) 260*7c478bd9Sstevel@tonic-gate * 261*7c478bd9Sstevel@tonic-gate * EVENT MANAGEMENT 262*7c478bd9Sstevel@tonic-gate * The event port file system creates a kmem_cache for internal allocation of 263*7c478bd9Sstevel@tonic-gate * event port structures. 264*7c478bd9Sstevel@tonic-gate * 265*7c478bd9Sstevel@tonic-gate * 1. Event source association with a port: 266*7c478bd9Sstevel@tonic-gate * The first step to do for event sources is to get associated with a port 267*7c478bd9Sstevel@tonic-gate * using the port_associate_ksource() function or adding an entry to the 268*7c478bd9Sstevel@tonic-gate * port_ksource_tab[]. An event source can get dissociated from a port 269*7c478bd9Sstevel@tonic-gate * using the port_dissociate_ksource() function. An entry in the 270*7c478bd9Sstevel@tonic-gate * port_ksource_tab[] implies that the source will be associated 271*7c478bd9Sstevel@tonic-gate * automatically with every new created port. 272*7c478bd9Sstevel@tonic-gate * The event source can deliver a callback function, which is used by the 273*7c478bd9Sstevel@tonic-gate * port to notify the event source about close(2). The idea is that 274*7c478bd9Sstevel@tonic-gate * in such a case the event source should free all allocated resources 275*7c478bd9Sstevel@tonic-gate * and it must return to the port all allocated slots/structures. 276*7c478bd9Sstevel@tonic-gate * The port_close() function will wait until all allocated event 277*7c478bd9Sstevel@tonic-gate * structures/slots are returned to the port. 278*7c478bd9Sstevel@tonic-gate * The callback function is not necessary when the event source does not 279*7c478bd9Sstevel@tonic-gate * maintain local resources, a second condition is that the event source 280*7c478bd9Sstevel@tonic-gate * can guarantee that allocated event slots will be returned without 281*7c478bd9Sstevel@tonic-gate * delay to the port (it will not block and sleep somewhere). 282*7c478bd9Sstevel@tonic-gate * 283*7c478bd9Sstevel@tonic-gate * 2. Reservation of an event slot / event structure 284*7c478bd9Sstevel@tonic-gate * The event port reliability is based on the reservation of an event "slot" 285*7c478bd9Sstevel@tonic-gate * (allocation of an event structure) by the event source as part of the 286*7c478bd9Sstevel@tonic-gate * application call. If the maximal number of event slots is exhausted then 287*7c478bd9Sstevel@tonic-gate * the event source can return a corresponding error code to the application. 288*7c478bd9Sstevel@tonic-gate * 289*7c478bd9Sstevel@tonic-gate * The port_alloc_event() function has to be used by event sources to 290*7c478bd9Sstevel@tonic-gate * allocate an event slot (reserve an event structure). The port_alloc_event() 291*7c478bd9Sstevel@tonic-gate * doesn not block and it will return a 0 value on success or an error code 292*7c478bd9Sstevel@tonic-gate * if it fails. 293*7c478bd9Sstevel@tonic-gate * An argument of port_alloc_event() is a flag which determines the behavior 294*7c478bd9Sstevel@tonic-gate * of the event after it was delivered to the application: 295*7c478bd9Sstevel@tonic-gate * PORT_ALLOC_DEFAULT : event slot becomes free after delivery to the 296*7c478bd9Sstevel@tonic-gate * application. 297*7c478bd9Sstevel@tonic-gate * PORT_ALLOC_PRIVATE : event slot remains under the control of the event 298*7c478bd9Sstevel@tonic-gate * source. This kind of slots can not be used for 299*7c478bd9Sstevel@tonic-gate * event delivery and should only be used internally 300*7c478bd9Sstevel@tonic-gate * by the event source. 301*7c478bd9Sstevel@tonic-gate * PORT_KEV_CACHED : event slot remains under the control of an event 302*7c478bd9Sstevel@tonic-gate * port cache. It does not become free after delivery 303*7c478bd9Sstevel@tonic-gate * to the application. 304*7c478bd9Sstevel@tonic-gate * PORT_ALLOC_SCACHED : event slot remains under the control of the event 305*7c478bd9Sstevel@tonic-gate * source. The event source takes the control over 306*7c478bd9Sstevel@tonic-gate * the slot after the event is delivered to the 307*7c478bd9Sstevel@tonic-gate * application. 308*7c478bd9Sstevel@tonic-gate * 309*7c478bd9Sstevel@tonic-gate * 3. Delivery of events to the event port 310*7c478bd9Sstevel@tonic-gate * Earlier allocated event structure/slot has to be used to deliver 311*7c478bd9Sstevel@tonic-gate * event data to the port. Event source has to use the function 312*7c478bd9Sstevel@tonic-gate * port_send_event(). The single argument is a pointer to the previously 313*7c478bd9Sstevel@tonic-gate * reserved event structure/slot. 314*7c478bd9Sstevel@tonic-gate * The portkev_events field of the port_kevent_t structure can be updated/set 315*7c478bd9Sstevel@tonic-gate * in two ways: 316*7c478bd9Sstevel@tonic-gate * 1. using the port_set_event() function, or 317*7c478bd9Sstevel@tonic-gate * 2. updating the portkev_events field out of the callback function: 318*7c478bd9Sstevel@tonic-gate * The event source can deliver a callback function to the port as an 319*7c478bd9Sstevel@tonic-gate * argument of port_init_event(). 320*7c478bd9Sstevel@tonic-gate * One of the arguments of the callback function is a pointer to the 321*7c478bd9Sstevel@tonic-gate * events field, which will be delivered to the application. 322*7c478bd9Sstevel@tonic-gate * (see Delivery of events to the application). 323*7c478bd9Sstevel@tonic-gate * Event structures/slots can be delivered to the event port only one time, 324*7c478bd9Sstevel@tonic-gate * they remain blocked until the data is delivered to the application and the 325*7c478bd9Sstevel@tonic-gate * slot becomes free or it is delivered back to the event source 326*7c478bd9Sstevel@tonic-gate * (PORT_ALLOC_SCACHED). The activation of the callback function mentioned above 327*7c478bd9Sstevel@tonic-gate * is at the same time the indicator for the event source that the event 328*7c478bd9Sstevel@tonic-gate * structure/slot is free for reuse. 329*7c478bd9Sstevel@tonic-gate * 330*7c478bd9Sstevel@tonic-gate * 4. Delivery of events to the application 331*7c478bd9Sstevel@tonic-gate * The events structures/slots delivered by event sources remain in the 332*7c478bd9Sstevel@tonic-gate * port queue until they are retrieved by the application or the port 333*7c478bd9Sstevel@tonic-gate * is closed (exit(2) also closes all opened file descriptors).. 334*7c478bd9Sstevel@tonic-gate * The application uses port_get() or port_getn() to retrieve events from 335*7c478bd9Sstevel@tonic-gate * a port. port_get() retrieves a single event structure/slot and port_getn() 336*7c478bd9Sstevel@tonic-gate * retrieves a list of event structures/slots. 337*7c478bd9Sstevel@tonic-gate * Both functions are able to poll for events and return immediately or they 338*7c478bd9Sstevel@tonic-gate * can specify a timeout value. 339*7c478bd9Sstevel@tonic-gate * Before the events are delivered to the application they are moved to a 340*7c478bd9Sstevel@tonic-gate * second temporary internal queue. The idea is to avoid lock collisions or 341*7c478bd9Sstevel@tonic-gate * contentions of the global queue lock. 342*7c478bd9Sstevel@tonic-gate * The global queue lock is used every time when an event source delivers 343*7c478bd9Sstevel@tonic-gate * new events to the port. 344*7c478bd9Sstevel@tonic-gate * The port_get() and port_getn() functions 345*7c478bd9Sstevel@tonic-gate * a) retrieve single events from the temporary queue, 346*7c478bd9Sstevel@tonic-gate * b) prepare the data to be passed to the application memory, 347*7c478bd9Sstevel@tonic-gate * c) activate the callback function of the event sources: 348*7c478bd9Sstevel@tonic-gate * - to get the latest event data, 349*7c478bd9Sstevel@tonic-gate * - the event source can free all allocated resources associated with the 350*7c478bd9Sstevel@tonic-gate * current event, 351*7c478bd9Sstevel@tonic-gate * - the event source can re-use the current event slot/structure 352*7c478bd9Sstevel@tonic-gate * - the event source can deny the delivery of the event to the application 353*7c478bd9Sstevel@tonic-gate * (e.g. because of the wrong process). 354*7c478bd9Sstevel@tonic-gate * d) put the event back to the temporary queue if the event delivery was denied 355*7c478bd9Sstevel@tonic-gate * e) repeat a) until d) as long as there are events in the queue and 356*7c478bd9Sstevel@tonic-gate * there is enough user space available. 357*7c478bd9Sstevel@tonic-gate * 358*7c478bd9Sstevel@tonic-gate * The loop described above could block for a very long time the global mutex, 359*7c478bd9Sstevel@tonic-gate * to avoid that a second mutex was introduced to synchronized concurrent 360*7c478bd9Sstevel@tonic-gate * threads accessing the temporary queue. 361*7c478bd9Sstevel@tonic-gate */ 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate static int64_t portfs(int, uintptr_t, uintptr_t, uintptr_t, uintptr_t, 364*7c478bd9Sstevel@tonic-gate uintptr_t); 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate static struct sysent port_sysent = { 367*7c478bd9Sstevel@tonic-gate 6, 368*7c478bd9Sstevel@tonic-gate SE_ARGC | SE_64RVAL | SE_NOUNLOAD, 369*7c478bd9Sstevel@tonic-gate (int (*)())portfs, 370*7c478bd9Sstevel@tonic-gate }; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate static struct modlsys modlsys = { 373*7c478bd9Sstevel@tonic-gate &mod_syscallops, "event ports", &port_sysent 374*7c478bd9Sstevel@tonic-gate }; 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate static int64_t 379*7c478bd9Sstevel@tonic-gate portfs32(uint32_t arg1, int32_t arg2, uint32_t arg3, uint32_t arg4, 380*7c478bd9Sstevel@tonic-gate uint32_t arg5, uint32_t arg6); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate static struct sysent port_sysent32 = { 383*7c478bd9Sstevel@tonic-gate 6, 384*7c478bd9Sstevel@tonic-gate SE_ARGC | SE_64RVAL | SE_NOUNLOAD, 385*7c478bd9Sstevel@tonic-gate (int (*)())portfs32, 386*7c478bd9Sstevel@tonic-gate }; 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = { 389*7c478bd9Sstevel@tonic-gate &mod_syscallops32, 390*7c478bd9Sstevel@tonic-gate "32-bit event ports syscalls", 391*7c478bd9Sstevel@tonic-gate &port_sysent32 392*7c478bd9Sstevel@tonic-gate }; 393*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 396*7c478bd9Sstevel@tonic-gate MODREV_1, 397*7c478bd9Sstevel@tonic-gate &modlsys, 398*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 399*7c478bd9Sstevel@tonic-gate &modlsys32, 400*7c478bd9Sstevel@tonic-gate #endif 401*7c478bd9Sstevel@tonic-gate NULL 402*7c478bd9Sstevel@tonic-gate }; 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate port_kstat_t port_kstat = { 405*7c478bd9Sstevel@tonic-gate { "ports", KSTAT_DATA_UINT32 } 406*7c478bd9Sstevel@tonic-gate }; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate dev_t portdev; 409*7c478bd9Sstevel@tonic-gate struct vnodeops *port_vnodeops; 410*7c478bd9Sstevel@tonic-gate struct vfs port_vfs; 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate extern rctl_hndl_t rc_process_portev; 413*7c478bd9Sstevel@tonic-gate extern rctl_hndl_t rc_project_portids; 414*7c478bd9Sstevel@tonic-gate extern void aio_close_port(void *, int, pid_t, int); 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate /* 417*7c478bd9Sstevel@tonic-gate * This table contains a list of event sources which need a static 418*7c478bd9Sstevel@tonic-gate * association with a port (every port). 419*7c478bd9Sstevel@tonic-gate * The last NULL entry in the table is required to detect "end of table". 420*7c478bd9Sstevel@tonic-gate */ 421*7c478bd9Sstevel@tonic-gate struct port_ksource port_ksource_tab[] = { 422*7c478bd9Sstevel@tonic-gate {PORT_SOURCE_AIO, aio_close_port, NULL, NULL}, 423*7c478bd9Sstevel@tonic-gate {0, NULL, NULL, NULL} 424*7c478bd9Sstevel@tonic-gate }; 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate /* local functions */ 427*7c478bd9Sstevel@tonic-gate static int port_getn(port_t *, port_event_t *, uint_t, uint_t *, 428*7c478bd9Sstevel@tonic-gate port_gettimer_t *); 429*7c478bd9Sstevel@tonic-gate static int port_sendn(int [], int [], uint_t, int, void *, uint_t *); 430*7c478bd9Sstevel@tonic-gate static int port_alert(port_t *, int, int, void *); 431*7c478bd9Sstevel@tonic-gate static int port_dispatch_event(port_t *, int, int, int, uintptr_t, void *); 432*7c478bd9Sstevel@tonic-gate static int port_send(port_t *, int, int, void *); 433*7c478bd9Sstevel@tonic-gate static int port_create(int *); 434*7c478bd9Sstevel@tonic-gate static int port_get_alert(port_alert_t *, port_event_t *); 435*7c478bd9Sstevel@tonic-gate static int port_copy_event(port_event_t *, port_kevent_t *, list_t *); 436*7c478bd9Sstevel@tonic-gate static int *port_errorn(int *, int, int, int); 437*7c478bd9Sstevel@tonic-gate static int port_noshare(void *, int *, pid_t, int, void *); 438*7c478bd9Sstevel@tonic-gate static int port_get_timeout(timespec_t *, timespec_t *, timespec_t **, int *, 439*7c478bd9Sstevel@tonic-gate int); 440*7c478bd9Sstevel@tonic-gate static void port_init(port_t *); 441*7c478bd9Sstevel@tonic-gate static void port_remove_alert(port_queue_t *); 442*7c478bd9Sstevel@tonic-gate static void port_add_ksource_local(port_t *, port_ksource_t *); 443*7c478bd9Sstevel@tonic-gate static void port_check_return_cond(port_queue_t *); 444*7c478bd9Sstevel@tonic-gate static void port_dequeue_thread(port_queue_t *, portget_t *); 445*7c478bd9Sstevel@tonic-gate static portget_t *port_queue_thread(port_queue_t *, uint_t); 446*7c478bd9Sstevel@tonic-gate static void port_kstat_init(void); 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 449*7c478bd9Sstevel@tonic-gate static int port_copy_event32(port_event32_t *, port_kevent_t *, list_t *); 450*7c478bd9Sstevel@tonic-gate #endif 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate int 453*7c478bd9Sstevel@tonic-gate _init(void) 454*7c478bd9Sstevel@tonic-gate { 455*7c478bd9Sstevel@tonic-gate static const fs_operation_def_t port_vfsops_template[] = { 456*7c478bd9Sstevel@tonic-gate NULL, NULL 457*7c478bd9Sstevel@tonic-gate }; 458*7c478bd9Sstevel@tonic-gate extern const fs_operation_def_t port_vnodeops_template[]; 459*7c478bd9Sstevel@tonic-gate vfsops_t *port_vfsops; 460*7c478bd9Sstevel@tonic-gate int error; 461*7c478bd9Sstevel@tonic-gate major_t major; 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate if ((major = getudev()) == (major_t)-1) 464*7c478bd9Sstevel@tonic-gate return (ENXIO); 465*7c478bd9Sstevel@tonic-gate portdev = makedevice(major, 0); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate /* Create a dummy vfs */ 468*7c478bd9Sstevel@tonic-gate error = vfs_makefsops(port_vfsops_template, &port_vfsops); 469*7c478bd9Sstevel@tonic-gate if (error) { 470*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "port init: bad vfs ops"); 471*7c478bd9Sstevel@tonic-gate return (error); 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate vfs_setops(&port_vfs, port_vfsops); 474*7c478bd9Sstevel@tonic-gate port_vfs.vfs_flag = VFS_RDONLY; 475*7c478bd9Sstevel@tonic-gate port_vfs.vfs_dev = portdev; 476*7c478bd9Sstevel@tonic-gate vfs_make_fsid(&(port_vfs.vfs_fsid), portdev, 0); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate error = vn_make_ops("portfs", port_vnodeops_template, &port_vnodeops); 479*7c478bd9Sstevel@tonic-gate if (error) { 480*7c478bd9Sstevel@tonic-gate vfs_freevfsops(port_vfsops); 481*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "port init: bad vnode ops"); 482*7c478bd9Sstevel@tonic-gate return (error); 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate mutex_init(&port_control.pc_mutex, NULL, MUTEX_DEFAULT, NULL); 486*7c478bd9Sstevel@tonic-gate port_control.pc_nents = 0; /* number of active ports */ 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate /* create kmem_cache for port event structures */ 489*7c478bd9Sstevel@tonic-gate port_control.pc_cache = kmem_cache_create("port_cache", 490*7c478bd9Sstevel@tonic-gate sizeof (port_kevent_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate port_kstat_init(); /* init port kstats */ 493*7c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate int 497*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 498*7c478bd9Sstevel@tonic-gate { 499*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate /* 503*7c478bd9Sstevel@tonic-gate * System call wrapper for all port related system calls from 32-bit programs. 504*7c478bd9Sstevel@tonic-gate */ 505*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 506*7c478bd9Sstevel@tonic-gate static int64_t 507*7c478bd9Sstevel@tonic-gate portfs32(uint32_t opcode, int32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, 508*7c478bd9Sstevel@tonic-gate uint32_t a4) 509*7c478bd9Sstevel@tonic-gate { 510*7c478bd9Sstevel@tonic-gate int64_t error; 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate switch (opcode & PORT_CODE_MASK) { 513*7c478bd9Sstevel@tonic-gate case PORT_GET: 514*7c478bd9Sstevel@tonic-gate error = portfs(PORT_GET, a0, a1, (int)a2, (int)a3, a4); 515*7c478bd9Sstevel@tonic-gate break; 516*7c478bd9Sstevel@tonic-gate case PORT_SENDN: 517*7c478bd9Sstevel@tonic-gate error = portfs(opcode, (uint32_t)a0, a1, a2, a3, a4); 518*7c478bd9Sstevel@tonic-gate break; 519*7c478bd9Sstevel@tonic-gate default: 520*7c478bd9Sstevel@tonic-gate error = portfs(opcode, a0, a1, a2, a3, a4); 521*7c478bd9Sstevel@tonic-gate break; 522*7c478bd9Sstevel@tonic-gate } 523*7c478bd9Sstevel@tonic-gate return (error); 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate /* 528*7c478bd9Sstevel@tonic-gate * System entry point for port functions. 529*7c478bd9Sstevel@tonic-gate * a0 is a port file descriptor (except for PORT_SENDN and PORT_CREATE). 530*7c478bd9Sstevel@tonic-gate * The libc uses PORT_SYS_NOPORT in functions which do not deliver a 531*7c478bd9Sstevel@tonic-gate * port file descriptor as first argument. 532*7c478bd9Sstevel@tonic-gate */ 533*7c478bd9Sstevel@tonic-gate static int64_t 534*7c478bd9Sstevel@tonic-gate portfs(int opcode, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, 535*7c478bd9Sstevel@tonic-gate uintptr_t a4) 536*7c478bd9Sstevel@tonic-gate { 537*7c478bd9Sstevel@tonic-gate rval_t r; 538*7c478bd9Sstevel@tonic-gate port_t *pp; 539*7c478bd9Sstevel@tonic-gate int error = 0; 540*7c478bd9Sstevel@tonic-gate uint_t nget; 541*7c478bd9Sstevel@tonic-gate file_t *fp; 542*7c478bd9Sstevel@tonic-gate port_gettimer_t port_timer; 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate r.r_vals = 0; 545*7c478bd9Sstevel@tonic-gate if (opcode & PORT_SYS_NOPORT) { 546*7c478bd9Sstevel@tonic-gate opcode &= PORT_CODE_MASK; 547*7c478bd9Sstevel@tonic-gate if (opcode == PORT_SENDN) { 548*7c478bd9Sstevel@tonic-gate error = port_sendn((int *)a0, (int *)a1, (uint_t)a2, 549*7c478bd9Sstevel@tonic-gate (int)a3, (void *)a4, (uint_t *)&r.r_val1); 550*7c478bd9Sstevel@tonic-gate if (error && (error != EIO)) 551*7c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(error)); 552*7c478bd9Sstevel@tonic-gate return (r.r_vals); 553*7c478bd9Sstevel@tonic-gate } 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate if (opcode == PORT_CREATE) { 556*7c478bd9Sstevel@tonic-gate error = port_create(&r.r_val1); 557*7c478bd9Sstevel@tonic-gate if (error) 558*7c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(error)); 559*7c478bd9Sstevel@tonic-gate return (r.r_vals); 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate /* opcodes using port as first argument (a0) */ 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate if ((fp = getf((int)a0)) == NULL) 566*7c478bd9Sstevel@tonic-gate return ((uintptr_t)set_errno(EBADF)); 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate if (fp->f_vnode->v_type != VPORT) { 569*7c478bd9Sstevel@tonic-gate releasef((int)a0); 570*7c478bd9Sstevel@tonic-gate return ((uintptr_t)set_errno(EBADFD)); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate pp = VTOEP(fp->f_vnode); 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate switch (opcode & PORT_CODE_MASK) { 576*7c478bd9Sstevel@tonic-gate case PORT_GET: 577*7c478bd9Sstevel@tonic-gate { 578*7c478bd9Sstevel@tonic-gate /* see PORT_GETN description */ 579*7c478bd9Sstevel@tonic-gate struct timespec timeout; 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate port_timer.pgt_flags = PORTGET_ONE; 582*7c478bd9Sstevel@tonic-gate port_timer.pgt_loop = 0; 583*7c478bd9Sstevel@tonic-gate port_timer.pgt_rqtp = NULL; 584*7c478bd9Sstevel@tonic-gate if (a4 != NULL) { 585*7c478bd9Sstevel@tonic-gate port_timer.pgt_timeout = &timeout; 586*7c478bd9Sstevel@tonic-gate timeout.tv_sec = (time_t)a2; 587*7c478bd9Sstevel@tonic-gate timeout.tv_nsec = (long)a3; 588*7c478bd9Sstevel@tonic-gate } else { 589*7c478bd9Sstevel@tonic-gate port_timer.pgt_timeout = NULL; 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate do { 592*7c478bd9Sstevel@tonic-gate nget = 1; 593*7c478bd9Sstevel@tonic-gate error = port_getn(pp, (port_event_t *)a1, 1, 594*7c478bd9Sstevel@tonic-gate (uint_t *)&nget, &port_timer); 595*7c478bd9Sstevel@tonic-gate } while (nget == 0 && error == 0 && port_timer.pgt_loop); 596*7c478bd9Sstevel@tonic-gate break; 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate case PORT_GETN: 599*7c478bd9Sstevel@tonic-gate { 600*7c478bd9Sstevel@tonic-gate /* 601*7c478bd9Sstevel@tonic-gate * port_getn() can only retrieve own or shareable events from 602*7c478bd9Sstevel@tonic-gate * other processes. The port_getn() function remains in the 603*7c478bd9Sstevel@tonic-gate * kernel until own or shareable events are available or the 604*7c478bd9Sstevel@tonic-gate * timeout elapses. 605*7c478bd9Sstevel@tonic-gate */ 606*7c478bd9Sstevel@tonic-gate port_timer.pgt_flags = 0; 607*7c478bd9Sstevel@tonic-gate port_timer.pgt_loop = 0; 608*7c478bd9Sstevel@tonic-gate port_timer.pgt_rqtp = NULL; 609*7c478bd9Sstevel@tonic-gate port_timer.pgt_timeout = (struct timespec *)a4; 610*7c478bd9Sstevel@tonic-gate do { 611*7c478bd9Sstevel@tonic-gate nget = a3; 612*7c478bd9Sstevel@tonic-gate error = port_getn(pp, (port_event_t *)a1, (uint_t)a2, 613*7c478bd9Sstevel@tonic-gate (uint_t *)&nget, &port_timer); 614*7c478bd9Sstevel@tonic-gate } while (nget == 0 && error == 0 && port_timer.pgt_loop); 615*7c478bd9Sstevel@tonic-gate r.r_val1 = nget; 616*7c478bd9Sstevel@tonic-gate r.r_val2 = error; 617*7c478bd9Sstevel@tonic-gate releasef((int)a0); 618*7c478bd9Sstevel@tonic-gate if (error && error != ETIME) 619*7c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(error)); 620*7c478bd9Sstevel@tonic-gate return (r.r_vals); 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate case PORT_ASSOCIATE: 623*7c478bd9Sstevel@tonic-gate { 624*7c478bd9Sstevel@tonic-gate /* currently only PORT_SOURCE_FD is implemented */ 625*7c478bd9Sstevel@tonic-gate if ((int)a1 != PORT_SOURCE_FD) { 626*7c478bd9Sstevel@tonic-gate error = EINVAL; 627*7c478bd9Sstevel@tonic-gate break; 628*7c478bd9Sstevel@tonic-gate } 629*7c478bd9Sstevel@tonic-gate error = port_associate_fd(pp, (int)a1, (uintptr_t)a2, (int)a3, 630*7c478bd9Sstevel@tonic-gate (void *)a4); 631*7c478bd9Sstevel@tonic-gate break; 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate case PORT_SEND: 634*7c478bd9Sstevel@tonic-gate { 635*7c478bd9Sstevel@tonic-gate /* user-defined events */ 636*7c478bd9Sstevel@tonic-gate error = port_send(pp, PORT_SOURCE_USER, (int)a1, (void *)a2); 637*7c478bd9Sstevel@tonic-gate break; 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate case PORT_DISPATCH: 640*7c478bd9Sstevel@tonic-gate { 641*7c478bd9Sstevel@tonic-gate /* 642*7c478bd9Sstevel@tonic-gate * library events, blocking 643*7c478bd9Sstevel@tonic-gate * Only events of type PORT_SOURCE_AIO are currently allowed. 644*7c478bd9Sstevel@tonic-gate */ 645*7c478bd9Sstevel@tonic-gate if ((int)a1 != PORT_SOURCE_AIO) { 646*7c478bd9Sstevel@tonic-gate error = EINVAL; 647*7c478bd9Sstevel@tonic-gate break; 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate error = port_dispatch_event(pp, (int)opcode, (int)a1, (int)a2, 650*7c478bd9Sstevel@tonic-gate (uintptr_t)a3, (void *)a4); 651*7c478bd9Sstevel@tonic-gate break; 652*7c478bd9Sstevel@tonic-gate } 653*7c478bd9Sstevel@tonic-gate case PORT_DISSOCIATE: 654*7c478bd9Sstevel@tonic-gate { 655*7c478bd9Sstevel@tonic-gate /* currently only PORT_SOURCE_FD is implemented */ 656*7c478bd9Sstevel@tonic-gate if ((int)a1 != PORT_SOURCE_FD) { 657*7c478bd9Sstevel@tonic-gate error = EINVAL; 658*7c478bd9Sstevel@tonic-gate break; 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate error = port_dissociate_fd(pp, (uintptr_t)a2); 661*7c478bd9Sstevel@tonic-gate break; 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate case PORT_ALERT: 664*7c478bd9Sstevel@tonic-gate { 665*7c478bd9Sstevel@tonic-gate if ((int)a2) /* a2 = events */ 666*7c478bd9Sstevel@tonic-gate error = port_alert(pp, (int)a1, (int)a2, (void *)a3); 667*7c478bd9Sstevel@tonic-gate else 668*7c478bd9Sstevel@tonic-gate port_remove_alert(&pp->port_queue); 669*7c478bd9Sstevel@tonic-gate break; 670*7c478bd9Sstevel@tonic-gate } 671*7c478bd9Sstevel@tonic-gate default: 672*7c478bd9Sstevel@tonic-gate error = EINVAL; 673*7c478bd9Sstevel@tonic-gate break; 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate releasef((int)a0); 677*7c478bd9Sstevel@tonic-gate if (error) 678*7c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(error)); 679*7c478bd9Sstevel@tonic-gate return (r.r_vals); 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /* 683*7c478bd9Sstevel@tonic-gate * System call to create a port. 684*7c478bd9Sstevel@tonic-gate * 685*7c478bd9Sstevel@tonic-gate * The port_create() function creates a vnode of type VPORT per port. 686*7c478bd9Sstevel@tonic-gate * The port control data is associated with the vnode as vnode private data. 687*7c478bd9Sstevel@tonic-gate * The port_create() function returns an event port file descriptor. 688*7c478bd9Sstevel@tonic-gate */ 689*7c478bd9Sstevel@tonic-gate static int 690*7c478bd9Sstevel@tonic-gate port_create(int *fdp) 691*7c478bd9Sstevel@tonic-gate { 692*7c478bd9Sstevel@tonic-gate port_t *pp; 693*7c478bd9Sstevel@tonic-gate vnode_t *vp; 694*7c478bd9Sstevel@tonic-gate struct file *fp; 695*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate /* initialize vnode and port private data */ 698*7c478bd9Sstevel@tonic-gate pp = kmem_zalloc(sizeof (port_t), KM_SLEEP); 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate pp->port_vnode = vn_alloc(KM_SLEEP); 701*7c478bd9Sstevel@tonic-gate vp = EPTOV(pp); 702*7c478bd9Sstevel@tonic-gate vn_setops(vp, port_vnodeops); 703*7c478bd9Sstevel@tonic-gate vp->v_type = VPORT; 704*7c478bd9Sstevel@tonic-gate vp->v_vfsp = &port_vfs; 705*7c478bd9Sstevel@tonic-gate vp->v_data = (caddr_t)pp; 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate mutex_enter(&port_control.pc_mutex); 708*7c478bd9Sstevel@tonic-gate /* 709*7c478bd9Sstevel@tonic-gate * Retrieve the maximal number of event ports allowed per system from 710*7c478bd9Sstevel@tonic-gate * the resource control: project.port-max-ids. 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 713*7c478bd9Sstevel@tonic-gate if (rctl_test(rc_project_portids, p->p_task->tk_proj->kpj_rctls, p, 714*7c478bd9Sstevel@tonic-gate port_control.pc_nents + 1, RCA_SAFE) & RCT_DENY) { 715*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 716*7c478bd9Sstevel@tonic-gate vn_free(vp); 717*7c478bd9Sstevel@tonic-gate kmem_free(pp, sizeof (port_t)); 718*7c478bd9Sstevel@tonic-gate mutex_exit(&port_control.pc_mutex); 719*7c478bd9Sstevel@tonic-gate return (EAGAIN); 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate /* 723*7c478bd9Sstevel@tonic-gate * Retrieve the maximal number of events allowed per port from 724*7c478bd9Sstevel@tonic-gate * the resource control: process.port-max-events. 725*7c478bd9Sstevel@tonic-gate */ 726*7c478bd9Sstevel@tonic-gate pp->port_max_events = rctl_enforced_value(rc_process_portev, 727*7c478bd9Sstevel@tonic-gate p->p_rctls, p); 728*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate /* allocate a new user file descriptor and a file structure */ 731*7c478bd9Sstevel@tonic-gate if (falloc(vp, 0, &fp, fdp)) { 732*7c478bd9Sstevel@tonic-gate /* 733*7c478bd9Sstevel@tonic-gate * If the file table is full, free allocated resources. 734*7c478bd9Sstevel@tonic-gate */ 735*7c478bd9Sstevel@tonic-gate vn_free(vp); 736*7c478bd9Sstevel@tonic-gate kmem_free(pp, sizeof (port_t)); 737*7c478bd9Sstevel@tonic-gate mutex_exit(&port_control.pc_mutex); 738*7c478bd9Sstevel@tonic-gate return (EMFILE); 739*7c478bd9Sstevel@tonic-gate } 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate /* set user file pointer */ 742*7c478bd9Sstevel@tonic-gate if (fdp != NULL) 743*7c478bd9Sstevel@tonic-gate setf(*fdp, fp); 744*7c478bd9Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate pp->port_fd = *fdp; 747*7c478bd9Sstevel@tonic-gate port_control.pc_nents++; 748*7c478bd9Sstevel@tonic-gate p->p_portcnt++; 749*7c478bd9Sstevel@tonic-gate port_kstat.pks_ports.value.ui32++; 750*7c478bd9Sstevel@tonic-gate mutex_exit(&port_control.pc_mutex); 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate /* initializes port private data */ 753*7c478bd9Sstevel@tonic-gate port_init(pp); 754*7c478bd9Sstevel@tonic-gate return (0); 755*7c478bd9Sstevel@tonic-gate } 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate /* 758*7c478bd9Sstevel@tonic-gate * port_init() initializes event port specific data 759*7c478bd9Sstevel@tonic-gate */ 760*7c478bd9Sstevel@tonic-gate static void 761*7c478bd9Sstevel@tonic-gate port_init(port_t *pp) 762*7c478bd9Sstevel@tonic-gate { 763*7c478bd9Sstevel@tonic-gate port_queue_t *portq; 764*7c478bd9Sstevel@tonic-gate port_ksource_t *pks; 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate mutex_init(&pp->port_mutex, NULL, MUTEX_DEFAULT, NULL); 767*7c478bd9Sstevel@tonic-gate portq = &pp->port_queue; 768*7c478bd9Sstevel@tonic-gate mutex_init(&portq->portq_mutex, NULL, MUTEX_DEFAULT, NULL); 769*7c478bd9Sstevel@tonic-gate pp->port_flags |= PORT_INIT; 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate /* 772*7c478bd9Sstevel@tonic-gate * If it is not enough memory available to satisfy a user 773*7c478bd9Sstevel@tonic-gate * request using a single port_getn() call then port_getn() 774*7c478bd9Sstevel@tonic-gate * will reduce the size of the list to PORT_MAX_LIST. 775*7c478bd9Sstevel@tonic-gate */ 776*7c478bd9Sstevel@tonic-gate pp->port_max_list = port_max_list; 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate /* Set timestamp entries required for fstat(2) requests */ 779*7c478bd9Sstevel@tonic-gate gethrestime(&pp->port_ctime); 780*7c478bd9Sstevel@tonic-gate pp->port_uid = crgetuid(curproc->p_cred); 781*7c478bd9Sstevel@tonic-gate pp->port_gid = crgetgid(curproc->p_cred); 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate /* initialize port queue structs */ 784*7c478bd9Sstevel@tonic-gate list_create(&portq->portq_list, sizeof (port_kevent_t), 785*7c478bd9Sstevel@tonic-gate offsetof(port_kevent_t, portkev_node)); 786*7c478bd9Sstevel@tonic-gate list_create(&portq->portq_get_list, sizeof (port_kevent_t), 787*7c478bd9Sstevel@tonic-gate offsetof(port_kevent_t, portkev_node)); 788*7c478bd9Sstevel@tonic-gate portq->portq_flags = 0; 789*7c478bd9Sstevel@tonic-gate pp->port_pid = curproc->p_pid; 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate /* Allocate cache skeleton for PORT_SOURCE_FD events */ 792*7c478bd9Sstevel@tonic-gate portq->portq_pcp = kmem_zalloc(sizeof (port_fdcache_t), KM_SLEEP); 793*7c478bd9Sstevel@tonic-gate mutex_init(&portq->portq_pcp->pc_lock, NULL, MUTEX_DEFAULT, NULL); 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate /* 796*7c478bd9Sstevel@tonic-gate * Allocate cache skeleton for association of event sources. 797*7c478bd9Sstevel@tonic-gate */ 798*7c478bd9Sstevel@tonic-gate mutex_init(&portq->portq_source_mutex, NULL, MUTEX_DEFAULT, NULL); 799*7c478bd9Sstevel@tonic-gate portq->portq_scache = kmem_zalloc( 800*7c478bd9Sstevel@tonic-gate PORT_SCACHE_SIZE * sizeof (port_source_t *), KM_SLEEP); 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate /* 803*7c478bd9Sstevel@tonic-gate * pre-associate some kernel sources with this port. 804*7c478bd9Sstevel@tonic-gate * The pre-association is required to create port_source_t 805*7c478bd9Sstevel@tonic-gate * structures for object association. 806*7c478bd9Sstevel@tonic-gate * Some sources can not get associated with a port before the first 807*7c478bd9Sstevel@tonic-gate * object association is requested. Another reason to pre_associate 808*7c478bd9Sstevel@tonic-gate * a particular source with a port is because of performance. 809*7c478bd9Sstevel@tonic-gate */ 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate for (pks = port_ksource_tab; pks->pks_source != 0; pks++) 812*7c478bd9Sstevel@tonic-gate port_add_ksource_local(pp, pks); 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate /* 816*7c478bd9Sstevel@tonic-gate * The port_add_ksource_local() function is being used to associate 817*7c478bd9Sstevel@tonic-gate * event sources with every new port. 818*7c478bd9Sstevel@tonic-gate * The event sources need to be added to port_ksource_tab[]. 819*7c478bd9Sstevel@tonic-gate */ 820*7c478bd9Sstevel@tonic-gate static void 821*7c478bd9Sstevel@tonic-gate port_add_ksource_local(port_t *pp, port_ksource_t *pks) 822*7c478bd9Sstevel@tonic-gate { 823*7c478bd9Sstevel@tonic-gate port_source_t *pse; 824*7c478bd9Sstevel@tonic-gate port_source_t **ps; 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate mutex_enter(&pp->port_queue.portq_source_mutex); 827*7c478bd9Sstevel@tonic-gate ps = &pp->port_queue.portq_scache[PORT_SHASH(pks->pks_source)]; 828*7c478bd9Sstevel@tonic-gate for (pse = *ps; pse != NULL; pse = pse->portsrc_next) { 829*7c478bd9Sstevel@tonic-gate if (pse->portsrc_source == pks->pks_source) 830*7c478bd9Sstevel@tonic-gate break; 831*7c478bd9Sstevel@tonic-gate } 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate if (pse == NULL) { 834*7c478bd9Sstevel@tonic-gate /* associate new source with the port */ 835*7c478bd9Sstevel@tonic-gate pse = kmem_zalloc(sizeof (port_source_t), KM_SLEEP); 836*7c478bd9Sstevel@tonic-gate pse->portsrc_source = pks->pks_source; 837*7c478bd9Sstevel@tonic-gate pse->portsrc_close = pks->pks_close; 838*7c478bd9Sstevel@tonic-gate pse->portsrc_closearg = pks->pks_closearg; 839*7c478bd9Sstevel@tonic-gate pse->portsrc_cnt = 1; 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate pks->pks_portsrc = pse; 842*7c478bd9Sstevel@tonic-gate if (*ps != NULL) 843*7c478bd9Sstevel@tonic-gate pse->portsrc_next = (*ps)->portsrc_next; 844*7c478bd9Sstevel@tonic-gate *ps = pse; 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate mutex_exit(&pp->port_queue.portq_source_mutex); 847*7c478bd9Sstevel@tonic-gate } 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate /* 850*7c478bd9Sstevel@tonic-gate * The port_send() function sends an event of type "source" to a 851*7c478bd9Sstevel@tonic-gate * port. This function is non-blocking. An event can be sent to 852*7c478bd9Sstevel@tonic-gate * a port as long as the number of events per port does not achieve the 853*7c478bd9Sstevel@tonic-gate * maximal allowed number of events. The max. number of events per port is 854*7c478bd9Sstevel@tonic-gate * defined by the resource control process.max-port-events. 855*7c478bd9Sstevel@tonic-gate * This function is used by the port library function port_send() 856*7c478bd9Sstevel@tonic-gate * and port_dispatch(). The port_send(3c) function is part of the 857*7c478bd9Sstevel@tonic-gate * event ports API and submits events of type PORT_SOURCE_USER. The 858*7c478bd9Sstevel@tonic-gate * port_dispatch() function is project private and it is used by library 859*7c478bd9Sstevel@tonic-gate * functions to submit events of other types than PORT_SOURCE_USER 860*7c478bd9Sstevel@tonic-gate * (e.g. PORT_SOURCE_AIO). 861*7c478bd9Sstevel@tonic-gate */ 862*7c478bd9Sstevel@tonic-gate static int 863*7c478bd9Sstevel@tonic-gate port_send(port_t *pp, int source, int events, void *user) 864*7c478bd9Sstevel@tonic-gate { 865*7c478bd9Sstevel@tonic-gate port_kevent_t *pev; 866*7c478bd9Sstevel@tonic-gate int error; 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate error = port_alloc_event_local(pp, source, PORT_ALLOC_DEFAULT, &pev); 869*7c478bd9Sstevel@tonic-gate if (error) 870*7c478bd9Sstevel@tonic-gate return (error); 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate pev->portkev_object = 0; 873*7c478bd9Sstevel@tonic-gate pev->portkev_events = events; 874*7c478bd9Sstevel@tonic-gate pev->portkev_user = user; 875*7c478bd9Sstevel@tonic-gate pev->portkev_callback = NULL; 876*7c478bd9Sstevel@tonic-gate pev->portkev_arg = NULL; 877*7c478bd9Sstevel@tonic-gate pev->portkev_flags = 0; 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate error = port_send_event(pev); 880*7c478bd9Sstevel@tonic-gate if (error) { 881*7c478bd9Sstevel@tonic-gate port_free_event_local(pev, 0); 882*7c478bd9Sstevel@tonic-gate return (error); 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate return (0); 885*7c478bd9Sstevel@tonic-gate } 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate /* 888*7c478bd9Sstevel@tonic-gate * The port_noshare() function returns 0 if the current event was generated 889*7c478bd9Sstevel@tonic-gate * by the same process. Otherwise is returns a value other than 0 and the 890*7c478bd9Sstevel@tonic-gate * event should not be delivered to the current processe. 891*7c478bd9Sstevel@tonic-gate * The port_noshare() function is normally used by the port_dispatch() 892*7c478bd9Sstevel@tonic-gate * function. The port_dispatch() function is project private and can only be 893*7c478bd9Sstevel@tonic-gate * used within the event port project. 894*7c478bd9Sstevel@tonic-gate * Currently the libaio uses the port_dispatch() function to deliver events 895*7c478bd9Sstevel@tonic-gate * of types PORT_SOURCE_AIO. 896*7c478bd9Sstevel@tonic-gate */ 897*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 898*7c478bd9Sstevel@tonic-gate static int 899*7c478bd9Sstevel@tonic-gate port_noshare(void *arg, int *events, pid_t pid, int flag, void *evp) 900*7c478bd9Sstevel@tonic-gate { 901*7c478bd9Sstevel@tonic-gate if (flag == PORT_CALLBACK_DEFAULT && curproc->p_pid != pid) 902*7c478bd9Sstevel@tonic-gate return (1); 903*7c478bd9Sstevel@tonic-gate return (0); 904*7c478bd9Sstevel@tonic-gate } 905*7c478bd9Sstevel@tonic-gate 906*7c478bd9Sstevel@tonic-gate /* 907*7c478bd9Sstevel@tonic-gate * The port_dispatch_event() function is project private and it is used by 908*7c478bd9Sstevel@tonic-gate * libraries involved in the project to deliver events to the port. 909*7c478bd9Sstevel@tonic-gate * port_dispatch will sleep and wait for enough resources to satisfy the 910*7c478bd9Sstevel@tonic-gate * request, if necessary. 911*7c478bd9Sstevel@tonic-gate * The library can specify if the delivered event is shareable with other 912*7c478bd9Sstevel@tonic-gate * processes (see PORT_SYS_NOSHARE flag). 913*7c478bd9Sstevel@tonic-gate */ 914*7c478bd9Sstevel@tonic-gate static int 915*7c478bd9Sstevel@tonic-gate port_dispatch_event(port_t *pp, int opcode, int source, int events, 916*7c478bd9Sstevel@tonic-gate uintptr_t object, void *user) 917*7c478bd9Sstevel@tonic-gate { 918*7c478bd9Sstevel@tonic-gate port_kevent_t *pev; 919*7c478bd9Sstevel@tonic-gate int error; 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate error = port_alloc_event_block(pp, source, PORT_ALLOC_DEFAULT, &pev); 922*7c478bd9Sstevel@tonic-gate if (error) 923*7c478bd9Sstevel@tonic-gate return (error); 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate pev->portkev_object = object; 926*7c478bd9Sstevel@tonic-gate pev->portkev_events = events; 927*7c478bd9Sstevel@tonic-gate pev->portkev_user = user; 928*7c478bd9Sstevel@tonic-gate pev->portkev_arg = NULL; 929*7c478bd9Sstevel@tonic-gate if (opcode & PORT_SYS_NOSHARE) { 930*7c478bd9Sstevel@tonic-gate pev->portkev_flags = PORT_KEV_NOSHARE; 931*7c478bd9Sstevel@tonic-gate pev->portkev_callback = port_noshare; 932*7c478bd9Sstevel@tonic-gate } else { 933*7c478bd9Sstevel@tonic-gate pev->portkev_flags = 0; 934*7c478bd9Sstevel@tonic-gate pev->portkev_callback = NULL; 935*7c478bd9Sstevel@tonic-gate } 936*7c478bd9Sstevel@tonic-gate 937*7c478bd9Sstevel@tonic-gate error = port_send_event(pev); 938*7c478bd9Sstevel@tonic-gate if (error) { 939*7c478bd9Sstevel@tonic-gate port_free_event_local(pev, 0); 940*7c478bd9Sstevel@tonic-gate return (error); 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate return (0); 943*7c478bd9Sstevel@tonic-gate } 944*7c478bd9Sstevel@tonic-gate 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate /* 947*7c478bd9Sstevel@tonic-gate * The port_sendn() function is the kernel implementation of the event 948*7c478bd9Sstevel@tonic-gate * port API function port_sendn(3c). 949*7c478bd9Sstevel@tonic-gate * This function is able to send an event to a list of event ports. 950*7c478bd9Sstevel@tonic-gate */ 951*7c478bd9Sstevel@tonic-gate static int 952*7c478bd9Sstevel@tonic-gate port_sendn(int ports[], int errors[], uint_t nent, int events, void *user, 953*7c478bd9Sstevel@tonic-gate uint_t *nget) 954*7c478bd9Sstevel@tonic-gate { 955*7c478bd9Sstevel@tonic-gate port_kevent_t *pev; 956*7c478bd9Sstevel@tonic-gate int errorcnt = 0; 957*7c478bd9Sstevel@tonic-gate int error = 0; 958*7c478bd9Sstevel@tonic-gate int count; 959*7c478bd9Sstevel@tonic-gate int port; 960*7c478bd9Sstevel@tonic-gate int *plist; 961*7c478bd9Sstevel@tonic-gate int *elist = NULL; 962*7c478bd9Sstevel@tonic-gate file_t *fp; 963*7c478bd9Sstevel@tonic-gate port_t *pp; 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate if (nent == 0 || nent > port_max_list) 966*7c478bd9Sstevel@tonic-gate return (EINVAL); 967*7c478bd9Sstevel@tonic-gate 968*7c478bd9Sstevel@tonic-gate plist = kmem_alloc(nent * sizeof (int), KM_SLEEP); 969*7c478bd9Sstevel@tonic-gate if (copyin((void *)ports, plist, nent * sizeof (int))) { 970*7c478bd9Sstevel@tonic-gate kmem_free(plist, nent * sizeof (int)); 971*7c478bd9Sstevel@tonic-gate return (EFAULT); 972*7c478bd9Sstevel@tonic-gate } 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate /* 975*7c478bd9Sstevel@tonic-gate * Scan the list for event port file descriptors and send the 976*7c478bd9Sstevel@tonic-gate * attached user event data embedded in a event of type 977*7c478bd9Sstevel@tonic-gate * PORT_SOURCE_USER to every event port in the list. 978*7c478bd9Sstevel@tonic-gate * If a list entry is not a valid event port then the corresponding 979*7c478bd9Sstevel@tonic-gate * error code will be stored in the errors[] list with the same 980*7c478bd9Sstevel@tonic-gate * list offset as in the ports[] list. 981*7c478bd9Sstevel@tonic-gate */ 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate for (count = 0; count < nent; count++) { 984*7c478bd9Sstevel@tonic-gate port = plist[count]; 985*7c478bd9Sstevel@tonic-gate if ((fp = getf(port)) == NULL) { 986*7c478bd9Sstevel@tonic-gate elist = port_errorn(elist, nent, EBADF, count); 987*7c478bd9Sstevel@tonic-gate errorcnt++; 988*7c478bd9Sstevel@tonic-gate continue; 989*7c478bd9Sstevel@tonic-gate } 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate pp = VTOEP(fp->f_vnode); 992*7c478bd9Sstevel@tonic-gate if (fp->f_vnode->v_type != VPORT) { 993*7c478bd9Sstevel@tonic-gate releasef(port); 994*7c478bd9Sstevel@tonic-gate elist = port_errorn(elist, nent, EBADFD, count); 995*7c478bd9Sstevel@tonic-gate errorcnt++; 996*7c478bd9Sstevel@tonic-gate continue; 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate error = port_alloc_event_local(pp, PORT_SOURCE_USER, 1000*7c478bd9Sstevel@tonic-gate PORT_ALLOC_DEFAULT, &pev); 1001*7c478bd9Sstevel@tonic-gate if (error) { 1002*7c478bd9Sstevel@tonic-gate releasef(port); 1003*7c478bd9Sstevel@tonic-gate elist = port_errorn(elist, nent, error, count); 1004*7c478bd9Sstevel@tonic-gate errorcnt++; 1005*7c478bd9Sstevel@tonic-gate continue; 1006*7c478bd9Sstevel@tonic-gate } 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate pev->portkev_object = 0; 1009*7c478bd9Sstevel@tonic-gate pev->portkev_events = events; 1010*7c478bd9Sstevel@tonic-gate pev->portkev_user = user; 1011*7c478bd9Sstevel@tonic-gate pev->portkev_callback = NULL; 1012*7c478bd9Sstevel@tonic-gate pev->portkev_arg = NULL; 1013*7c478bd9Sstevel@tonic-gate pev->portkev_flags = 0; 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate (void) port_send_event(pev); 1016*7c478bd9Sstevel@tonic-gate releasef(port); 1017*7c478bd9Sstevel@tonic-gate } 1018*7c478bd9Sstevel@tonic-gate if (errorcnt) { 1019*7c478bd9Sstevel@tonic-gate error = EIO; 1020*7c478bd9Sstevel@tonic-gate if (copyout(elist, (void *)errors, nent * sizeof (int))) 1021*7c478bd9Sstevel@tonic-gate error = EFAULT; 1022*7c478bd9Sstevel@tonic-gate kmem_free(elist, nent * sizeof (int)); 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate *nget = nent - errorcnt; 1025*7c478bd9Sstevel@tonic-gate kmem_free(plist, nent * sizeof (int)); 1026*7c478bd9Sstevel@tonic-gate return (error); 1027*7c478bd9Sstevel@tonic-gate } 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate static int * 1030*7c478bd9Sstevel@tonic-gate port_errorn(int *elist, int nent, int error, int index) 1031*7c478bd9Sstevel@tonic-gate { 1032*7c478bd9Sstevel@tonic-gate if (elist == NULL) 1033*7c478bd9Sstevel@tonic-gate elist = kmem_zalloc(nent * sizeof (int), KM_SLEEP); 1034*7c478bd9Sstevel@tonic-gate elist[index] = error; 1035*7c478bd9Sstevel@tonic-gate return (elist); 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate /* 1039*7c478bd9Sstevel@tonic-gate * port_alert() 1040*7c478bd9Sstevel@tonic-gate * The port_alert() funcion is a high priority event and it is always set 1041*7c478bd9Sstevel@tonic-gate * on top of the queue. It is also delivered as single event. 1042*7c478bd9Sstevel@tonic-gate * flags: 1043*7c478bd9Sstevel@tonic-gate * - SET :overwrite current alert data 1044*7c478bd9Sstevel@tonic-gate * - UPDATE:set alert data or return EBUSY if alert mode is already set 1045*7c478bd9Sstevel@tonic-gate * 1046*7c478bd9Sstevel@tonic-gate * - set the ALERT flag 1047*7c478bd9Sstevel@tonic-gate * - wakeup all sleeping threads 1048*7c478bd9Sstevel@tonic-gate */ 1049*7c478bd9Sstevel@tonic-gate static int 1050*7c478bd9Sstevel@tonic-gate port_alert(port_t *pp, int flags, int events, void *user) 1051*7c478bd9Sstevel@tonic-gate { 1052*7c478bd9Sstevel@tonic-gate port_queue_t *portq; 1053*7c478bd9Sstevel@tonic-gate portget_t *pgetp; 1054*7c478bd9Sstevel@tonic-gate port_alert_t *pa; 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate if ((flags & PORT_ALERT_INVALID) == PORT_ALERT_INVALID) 1057*7c478bd9Sstevel@tonic-gate return (EINVAL); 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate portq = &pp->port_queue; 1060*7c478bd9Sstevel@tonic-gate pa = &portq->portq_alert; 1061*7c478bd9Sstevel@tonic-gate mutex_enter(&portq->portq_mutex); 1062*7c478bd9Sstevel@tonic-gate 1063*7c478bd9Sstevel@tonic-gate /* check alert conditions */ 1064*7c478bd9Sstevel@tonic-gate if (flags == PORT_ALERT_UPDATE) { 1065*7c478bd9Sstevel@tonic-gate if (portq->portq_flags & PORTQ_ALERT) { 1066*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1067*7c478bd9Sstevel@tonic-gate return (EBUSY); 1068*7c478bd9Sstevel@tonic-gate } 1069*7c478bd9Sstevel@tonic-gate } 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate /* 1072*7c478bd9Sstevel@tonic-gate * Store alert data in the port to be delivered to threads 1073*7c478bd9Sstevel@tonic-gate * which are using port_get(n) to retrieve events. 1074*7c478bd9Sstevel@tonic-gate */ 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate portq->portq_flags |= PORTQ_ALERT; 1077*7c478bd9Sstevel@tonic-gate pa->portal_events = events; /* alert info */ 1078*7c478bd9Sstevel@tonic-gate pa->portal_pid = curproc->p_pid; /* process owner */ 1079*7c478bd9Sstevel@tonic-gate pa->portal_object = 0; /* no object */ 1080*7c478bd9Sstevel@tonic-gate pa->portal_user = user; /* user alert data */ 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate /* alert and deliver alert data to waiting threads */ 1083*7c478bd9Sstevel@tonic-gate pgetp = portq->portq_thread; 1084*7c478bd9Sstevel@tonic-gate if (pgetp == NULL) { 1085*7c478bd9Sstevel@tonic-gate /* no threads waiting for events */ 1086*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1087*7c478bd9Sstevel@tonic-gate return (0); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate /* 1091*7c478bd9Sstevel@tonic-gate * Set waiting threads in alert mode (PORTGET_ALERT).. 1092*7c478bd9Sstevel@tonic-gate * Every thread waiting for events already allocated a portget_t 1093*7c478bd9Sstevel@tonic-gate * structure to sleep on. 1094*7c478bd9Sstevel@tonic-gate * The port alert arguments are stored in the portget_t structure. 1095*7c478bd9Sstevel@tonic-gate * The PORTGET_ALERT flag is set to indicate the thread to return 1096*7c478bd9Sstevel@tonic-gate * immediately with the alert event. 1097*7c478bd9Sstevel@tonic-gate */ 1098*7c478bd9Sstevel@tonic-gate do { 1099*7c478bd9Sstevel@tonic-gate if ((pgetp->portget_state & PORTGET_ALERT) == 0) { 1100*7c478bd9Sstevel@tonic-gate pa = &pgetp->portget_alert; 1101*7c478bd9Sstevel@tonic-gate pa->portal_events = events; 1102*7c478bd9Sstevel@tonic-gate pa->portal_object = 0; 1103*7c478bd9Sstevel@tonic-gate pa->portal_user = user; 1104*7c478bd9Sstevel@tonic-gate pgetp->portget_state |= PORTGET_ALERT; 1105*7c478bd9Sstevel@tonic-gate cv_signal(&pgetp->portget_cv); 1106*7c478bd9Sstevel@tonic-gate } 1107*7c478bd9Sstevel@tonic-gate } while ((pgetp = pgetp->portget_next) != portq->portq_thread); 1108*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1109*7c478bd9Sstevel@tonic-gate return (0); 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate /* 1113*7c478bd9Sstevel@tonic-gate * Clear alert state of the port 1114*7c478bd9Sstevel@tonic-gate */ 1115*7c478bd9Sstevel@tonic-gate static void 1116*7c478bd9Sstevel@tonic-gate port_remove_alert(port_queue_t *portq) 1117*7c478bd9Sstevel@tonic-gate { 1118*7c478bd9Sstevel@tonic-gate mutex_enter(&portq->portq_mutex); 1119*7c478bd9Sstevel@tonic-gate portq->portq_flags &= ~PORTQ_ALERT; 1120*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate /* 1124*7c478bd9Sstevel@tonic-gate * The port_getn() function is used to retrieve events from a port. 1125*7c478bd9Sstevel@tonic-gate * 1126*7c478bd9Sstevel@tonic-gate * The port_getn() function returns immediately if there are enough events 1127*7c478bd9Sstevel@tonic-gate * available in the port to satisfy the request or if the port is in alert 1128*7c478bd9Sstevel@tonic-gate * mode (see port_alert(3c)). 1129*7c478bd9Sstevel@tonic-gate * The timeout argument of port_getn(3c) -which is embedded in the 1130*7c478bd9Sstevel@tonic-gate * port_gettimer_t structure- specifies if the system call should block or if it 1131*7c478bd9Sstevel@tonic-gate * should return immediately depending on the number of events available. 1132*7c478bd9Sstevel@tonic-gate * This function is internally used by port_getn(3c) as well as by 1133*7c478bd9Sstevel@tonic-gate * port_get(3c). 1134*7c478bd9Sstevel@tonic-gate */ 1135*7c478bd9Sstevel@tonic-gate static int 1136*7c478bd9Sstevel@tonic-gate port_getn(port_t *pp, port_event_t *uevp, uint_t max, uint_t *nget, 1137*7c478bd9Sstevel@tonic-gate port_gettimer_t *pgt) 1138*7c478bd9Sstevel@tonic-gate { 1139*7c478bd9Sstevel@tonic-gate port_queue_t *portq; 1140*7c478bd9Sstevel@tonic-gate port_kevent_t *pev; 1141*7c478bd9Sstevel@tonic-gate port_kevent_t *lev; 1142*7c478bd9Sstevel@tonic-gate int error = 0; 1143*7c478bd9Sstevel@tonic-gate uint_t nmax; 1144*7c478bd9Sstevel@tonic-gate uint_t nevents; 1145*7c478bd9Sstevel@tonic-gate uint_t eventsz; 1146*7c478bd9Sstevel@tonic-gate port_event_t *kevp; 1147*7c478bd9Sstevel@tonic-gate list_t *glist; 1148*7c478bd9Sstevel@tonic-gate uint_t tnent; 1149*7c478bd9Sstevel@tonic-gate int rval; 1150*7c478bd9Sstevel@tonic-gate int blocking = -1; 1151*7c478bd9Sstevel@tonic-gate int timecheck; 1152*7c478bd9Sstevel@tonic-gate int flag; 1153*7c478bd9Sstevel@tonic-gate timespec_t rqtime; 1154*7c478bd9Sstevel@tonic-gate timespec_t *rqtp = NULL; 1155*7c478bd9Sstevel@tonic-gate portget_t *pgetp; 1156*7c478bd9Sstevel@tonic-gate void *results; 1157*7c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate flag = pgt->pgt_flags; 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate if (*nget > max && max > 0) 1162*7c478bd9Sstevel@tonic-gate return (EINVAL); 1163*7c478bd9Sstevel@tonic-gate 1164*7c478bd9Sstevel@tonic-gate portq = &pp->port_queue; 1165*7c478bd9Sstevel@tonic-gate mutex_enter(&portq->portq_mutex); 1166*7c478bd9Sstevel@tonic-gate if (max == 0) { 1167*7c478bd9Sstevel@tonic-gate /* 1168*7c478bd9Sstevel@tonic-gate * Return number of objects with events 1169*7c478bd9Sstevel@tonic-gate * The portq_block_mutex is required to synchronize this 1170*7c478bd9Sstevel@tonic-gate * thread with another possible thread, which could be 1171*7c478bd9Sstevel@tonic-gate * retrieving events from the port queue. 1172*7c478bd9Sstevel@tonic-gate */ 1173*7c478bd9Sstevel@tonic-gate mutex_enter(&portq->portq_block_mutex); 1174*7c478bd9Sstevel@tonic-gate /* 1175*7c478bd9Sstevel@tonic-gate * Check if a second thread is currently retrieving events 1176*7c478bd9Sstevel@tonic-gate * and it is using the temporary event queue. 1177*7c478bd9Sstevel@tonic-gate */ 1178*7c478bd9Sstevel@tonic-gate if (portq->portq_tnent) { 1179*7c478bd9Sstevel@tonic-gate /* put remaining events back to the port queue */ 1180*7c478bd9Sstevel@tonic-gate port_push_eventq(portq); 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate *nget = portq->portq_nent; 1183*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_block_mutex); 1184*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1185*7c478bd9Sstevel@tonic-gate return (0); 1186*7c478bd9Sstevel@tonic-gate } 1187*7c478bd9Sstevel@tonic-gate 1188*7c478bd9Sstevel@tonic-gate if (uevp == NULL) { 1189*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1190*7c478bd9Sstevel@tonic-gate return (EFAULT); 1191*7c478bd9Sstevel@tonic-gate } 1192*7c478bd9Sstevel@tonic-gate if (*nget == 0) { /* no events required */ 1193*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1194*7c478bd9Sstevel@tonic-gate return (0); 1195*7c478bd9Sstevel@tonic-gate } 1196*7c478bd9Sstevel@tonic-gate 1197*7c478bd9Sstevel@tonic-gate /* port is being closed ... */ 1198*7c478bd9Sstevel@tonic-gate if (portq->portq_flags & PORTQ_CLOSE) { 1199*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1200*7c478bd9Sstevel@tonic-gate return (EBADFD); 1201*7c478bd9Sstevel@tonic-gate } 1202*7c478bd9Sstevel@tonic-gate 1203*7c478bd9Sstevel@tonic-gate /* return immediately if port in alert mode */ 1204*7c478bd9Sstevel@tonic-gate if (portq->portq_flags & PORTQ_ALERT) { 1205*7c478bd9Sstevel@tonic-gate error = port_get_alert(&portq->portq_alert, uevp); 1206*7c478bd9Sstevel@tonic-gate if (error == 0) 1207*7c478bd9Sstevel@tonic-gate *nget = 1; 1208*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1209*7c478bd9Sstevel@tonic-gate return (error); 1210*7c478bd9Sstevel@tonic-gate } 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate portq->portq_thrcnt++; 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate /* 1215*7c478bd9Sstevel@tonic-gate * Now check if the completed events satisfy the 1216*7c478bd9Sstevel@tonic-gate * "wait" requirements of the current thread: 1217*7c478bd9Sstevel@tonic-gate */ 1218*7c478bd9Sstevel@tonic-gate 1219*7c478bd9Sstevel@tonic-gate if (pgt->pgt_loop) { 1220*7c478bd9Sstevel@tonic-gate /* 1221*7c478bd9Sstevel@tonic-gate * loop entry of same thread 1222*7c478bd9Sstevel@tonic-gate * pgt_loop is set when the current thread returns 1223*7c478bd9Sstevel@tonic-gate * prematurely from this function. That could happen 1224*7c478bd9Sstevel@tonic-gate * when a port is being shared between processes and 1225*7c478bd9Sstevel@tonic-gate * this thread could not find events to return. 1226*7c478bd9Sstevel@tonic-gate * It is not allowed to a thread to retrieve non-shareable 1227*7c478bd9Sstevel@tonic-gate * events generated in other processes. 1228*7c478bd9Sstevel@tonic-gate * PORTQ_WAIT_EVENTS is set when a thread already 1229*7c478bd9Sstevel@tonic-gate * checked the current event queue and no new events 1230*7c478bd9Sstevel@tonic-gate * are added to the queue. 1231*7c478bd9Sstevel@tonic-gate */ 1232*7c478bd9Sstevel@tonic-gate if (((portq->portq_flags & PORTQ_WAIT_EVENTS) == 0) && 1233*7c478bd9Sstevel@tonic-gate (portq->portq_nent >= *nget)) { 1234*7c478bd9Sstevel@tonic-gate /* some new events arrived ...check them */ 1235*7c478bd9Sstevel@tonic-gate goto portnowait; 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate rqtp = pgt->pgt_rqtp; 1238*7c478bd9Sstevel@tonic-gate timecheck = pgt->pgt_timecheck; 1239*7c478bd9Sstevel@tonic-gate pgt->pgt_flags |= PORTGET_WAIT_EVENTS; 1240*7c478bd9Sstevel@tonic-gate } else { 1241*7c478bd9Sstevel@tonic-gate /* check if enough events are available ... */ 1242*7c478bd9Sstevel@tonic-gate if (portq->portq_nent >= *nget) 1243*7c478bd9Sstevel@tonic-gate goto portnowait; 1244*7c478bd9Sstevel@tonic-gate /* 1245*7c478bd9Sstevel@tonic-gate * There are not enough events available to satisfy 1246*7c478bd9Sstevel@tonic-gate * the request, check timeout value and wait for 1247*7c478bd9Sstevel@tonic-gate * incoming events. 1248*7c478bd9Sstevel@tonic-gate */ 1249*7c478bd9Sstevel@tonic-gate error = port_get_timeout(pgt->pgt_timeout, &rqtime, &rqtp, 1250*7c478bd9Sstevel@tonic-gate &blocking, flag); 1251*7c478bd9Sstevel@tonic-gate if (error) { 1252*7c478bd9Sstevel@tonic-gate port_check_return_cond(portq); 1253*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1254*7c478bd9Sstevel@tonic-gate return (error); 1255*7c478bd9Sstevel@tonic-gate } 1256*7c478bd9Sstevel@tonic-gate 1257*7c478bd9Sstevel@tonic-gate if (blocking == 0) /* don't block, check fired events */ 1258*7c478bd9Sstevel@tonic-gate goto portnowait; 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate if (rqtp != NULL) { 1261*7c478bd9Sstevel@tonic-gate timespec_t now; 1262*7c478bd9Sstevel@tonic-gate timecheck = timechanged; 1263*7c478bd9Sstevel@tonic-gate gethrestime(&now); 1264*7c478bd9Sstevel@tonic-gate timespecadd(rqtp, &now); 1265*7c478bd9Sstevel@tonic-gate } 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate /* enqueue thread in the list of waiting threads */ 1269*7c478bd9Sstevel@tonic-gate pgetp = port_queue_thread(portq, *nget); 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate 1272*7c478bd9Sstevel@tonic-gate /* Wait here until return conditions met */ 1273*7c478bd9Sstevel@tonic-gate for (;;) { 1274*7c478bd9Sstevel@tonic-gate if (pgetp->portget_state & PORTGET_ALERT) { 1275*7c478bd9Sstevel@tonic-gate /* reap alert event and return */ 1276*7c478bd9Sstevel@tonic-gate error = port_get_alert(&pgetp->portget_alert, uevp); 1277*7c478bd9Sstevel@tonic-gate if (error) 1278*7c478bd9Sstevel@tonic-gate *nget = 0; 1279*7c478bd9Sstevel@tonic-gate else 1280*7c478bd9Sstevel@tonic-gate *nget = 1; 1281*7c478bd9Sstevel@tonic-gate port_dequeue_thread(&pp->port_queue, pgetp); 1282*7c478bd9Sstevel@tonic-gate portq->portq_thrcnt--; 1283*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1284*7c478bd9Sstevel@tonic-gate return (error); 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate /* 1288*7c478bd9Sstevel@tonic-gate * Check if some other thread is already retrieving 1289*7c478bd9Sstevel@tonic-gate * events (portq_getn > 0). 1290*7c478bd9Sstevel@tonic-gate */ 1291*7c478bd9Sstevel@tonic-gate 1292*7c478bd9Sstevel@tonic-gate if ((portq->portq_getn == 0) && 1293*7c478bd9Sstevel@tonic-gate ((portq)->portq_nent >= *nget) && 1294*7c478bd9Sstevel@tonic-gate (!((pgt)->pgt_flags & PORTGET_WAIT_EVENTS) || 1295*7c478bd9Sstevel@tonic-gate !((portq)->portq_flags & PORTQ_WAIT_EVENTS))) 1296*7c478bd9Sstevel@tonic-gate break; 1297*7c478bd9Sstevel@tonic-gate 1298*7c478bd9Sstevel@tonic-gate if (portq->portq_flags & PORTQ_CLOSE) { 1299*7c478bd9Sstevel@tonic-gate error = EBADFD; 1300*7c478bd9Sstevel@tonic-gate break; 1301*7c478bd9Sstevel@tonic-gate } 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate rval = cv_waituntil_sig(&pgetp->portget_cv, &portq->portq_mutex, 1304*7c478bd9Sstevel@tonic-gate rqtp, timecheck); 1305*7c478bd9Sstevel@tonic-gate 1306*7c478bd9Sstevel@tonic-gate if (rval <= 0) { 1307*7c478bd9Sstevel@tonic-gate error = (rval == 0) ? EINTR : ETIME; 1308*7c478bd9Sstevel@tonic-gate break; 1309*7c478bd9Sstevel@tonic-gate } 1310*7c478bd9Sstevel@tonic-gate } 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate /* take thread out of the wait queue */ 1313*7c478bd9Sstevel@tonic-gate port_dequeue_thread(portq, pgetp); 1314*7c478bd9Sstevel@tonic-gate 1315*7c478bd9Sstevel@tonic-gate if (error != 0 && (error == EINTR || error == EBADFD || 1316*7c478bd9Sstevel@tonic-gate (error == ETIME && flag))) { 1317*7c478bd9Sstevel@tonic-gate /* return without events */ 1318*7c478bd9Sstevel@tonic-gate port_check_return_cond(portq); 1319*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1320*7c478bd9Sstevel@tonic-gate return (error); 1321*7c478bd9Sstevel@tonic-gate } 1322*7c478bd9Sstevel@tonic-gate 1323*7c478bd9Sstevel@tonic-gate portnowait: 1324*7c478bd9Sstevel@tonic-gate nmax = max < portq->portq_nent ? max : portq->portq_nent; 1325*7c478bd9Sstevel@tonic-gate 1326*7c478bd9Sstevel@tonic-gate /* 1327*7c478bd9Sstevel@tonic-gate * Move port event queue to a temporary event queue . 1328*7c478bd9Sstevel@tonic-gate * New incoming events will be continue be posted to the event queue 1329*7c478bd9Sstevel@tonic-gate * and they will not be considered by the current thread. 1330*7c478bd9Sstevel@tonic-gate * The idea is to avoid lock contentions or an often locking/unlocking 1331*7c478bd9Sstevel@tonic-gate * of the port queue mutex. The contention and performance degradation 1332*7c478bd9Sstevel@tonic-gate * could happen because: 1333*7c478bd9Sstevel@tonic-gate * a) incoming events use the port queue mutex to enqueue new events and 1334*7c478bd9Sstevel@tonic-gate * b) before the event can be delivered to the application it is 1335*7c478bd9Sstevel@tonic-gate * necessary to notify the event sources about the event delivery. 1336*7c478bd9Sstevel@tonic-gate * Sometimes the event sources can require a long time to return and 1337*7c478bd9Sstevel@tonic-gate * the queue mutex would block incoming events. 1338*7c478bd9Sstevel@tonic-gate * During this time incoming events (port_send_event()) do not need 1339*7c478bd9Sstevel@tonic-gate * to awake threads waiting for events. Before the current thread 1340*7c478bd9Sstevel@tonic-gate * returns it will check the conditions to awake other waiting threads. 1341*7c478bd9Sstevel@tonic-gate */ 1342*7c478bd9Sstevel@tonic-gate portq->portq_getn++; /* number of threads retrieving events */ 1343*7c478bd9Sstevel@tonic-gate mutex_enter(&portq->portq_block_mutex); /* block other threads here */ 1344*7c478bd9Sstevel@tonic-gate if (portq->portq_tnent) { 1345*7c478bd9Sstevel@tonic-gate /* 1346*7c478bd9Sstevel@tonic-gate * Move remaining events from previous thread back to the 1347*7c478bd9Sstevel@tonic-gate * port event queue. 1348*7c478bd9Sstevel@tonic-gate */ 1349*7c478bd9Sstevel@tonic-gate port_push_eventq(portq); 1350*7c478bd9Sstevel@tonic-gate } 1351*7c478bd9Sstevel@tonic-gate /* move port event queue to a temporary queue */ 1352*7c478bd9Sstevel@tonic-gate list_move_tail(&portq->portq_get_list, &portq->portq_list); 1353*7c478bd9Sstevel@tonic-gate glist = &portq->portq_get_list; /* use temporary event queue */ 1354*7c478bd9Sstevel@tonic-gate tnent = portq->portq_nent; /* get current number of events */ 1355*7c478bd9Sstevel@tonic-gate portq->portq_nent = 0; /* no events in the port event queue */ 1356*7c478bd9Sstevel@tonic-gate portq->portq_flags |= PORTQ_WAIT_EVENTS; /* detect incoming events */ 1357*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); /* event queue can be reused now */ 1358*7c478bd9Sstevel@tonic-gate 1359*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 1360*7c478bd9Sstevel@tonic-gate eventsz = sizeof (port_event_t); 1361*7c478bd9Sstevel@tonic-gate kevp = kmem_alloc(eventsz * nmax, KM_NOSLEEP); 1362*7c478bd9Sstevel@tonic-gate if (kevp == NULL) { 1363*7c478bd9Sstevel@tonic-gate if (nmax > pp->port_max_list) 1364*7c478bd9Sstevel@tonic-gate nmax = pp->port_max_list; 1365*7c478bd9Sstevel@tonic-gate kevp = kmem_alloc(eventsz * nmax, KM_SLEEP); 1366*7c478bd9Sstevel@tonic-gate } 1367*7c478bd9Sstevel@tonic-gate results = kevp; 1368*7c478bd9Sstevel@tonic-gate lev = NULL; /* start with first event in the queue */ 1369*7c478bd9Sstevel@tonic-gate for (nevents = 0; nevents < nmax; ) { 1370*7c478bd9Sstevel@tonic-gate pev = port_get_kevent(glist, lev); 1371*7c478bd9Sstevel@tonic-gate if (pev == NULL) /* no more events available */ 1372*7c478bd9Sstevel@tonic-gate break; 1373*7c478bd9Sstevel@tonic-gate if (pev->portkev_flags & PORT_KEV_FREE) { 1374*7c478bd9Sstevel@tonic-gate /* Just discard event */ 1375*7c478bd9Sstevel@tonic-gate list_remove(glist, pev); 1376*7c478bd9Sstevel@tonic-gate pev->portkev_flags &= ~(PORT_CLEANUP_DONE); 1377*7c478bd9Sstevel@tonic-gate if (PORT_FREE_EVENT(pev)) 1378*7c478bd9Sstevel@tonic-gate port_free_event_local(pev, 0); 1379*7c478bd9Sstevel@tonic-gate tnent--; 1380*7c478bd9Sstevel@tonic-gate continue; 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate /* move event data to copyout list */ 1384*7c478bd9Sstevel@tonic-gate if (port_copy_event(&kevp[nevents], pev, glist)) { 1385*7c478bd9Sstevel@tonic-gate /* 1386*7c478bd9Sstevel@tonic-gate * Event can not be delivered to the 1387*7c478bd9Sstevel@tonic-gate * current process. 1388*7c478bd9Sstevel@tonic-gate */ 1389*7c478bd9Sstevel@tonic-gate if (lev != NULL) 1390*7c478bd9Sstevel@tonic-gate list_insert_after(glist, lev, pev); 1391*7c478bd9Sstevel@tonic-gate else 1392*7c478bd9Sstevel@tonic-gate list_insert_head(glist, pev); 1393*7c478bd9Sstevel@tonic-gate lev = pev; /* last checked event */ 1394*7c478bd9Sstevel@tonic-gate } else { 1395*7c478bd9Sstevel@tonic-gate nevents++; /* # of events ready */ 1396*7c478bd9Sstevel@tonic-gate } 1397*7c478bd9Sstevel@tonic-gate } 1398*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1399*7c478bd9Sstevel@tonic-gate } else { 1400*7c478bd9Sstevel@tonic-gate port_event32_t *kevp32; 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate eventsz = sizeof (port_event32_t); 1403*7c478bd9Sstevel@tonic-gate kevp32 = kmem_alloc(eventsz * nmax, KM_NOSLEEP); 1404*7c478bd9Sstevel@tonic-gate if (kevp32 == NULL) { 1405*7c478bd9Sstevel@tonic-gate if (nmax > pp->port_max_list) 1406*7c478bd9Sstevel@tonic-gate nmax = pp->port_max_list; 1407*7c478bd9Sstevel@tonic-gate kevp32 = kmem_alloc(eventsz * nmax, KM_SLEEP); 1408*7c478bd9Sstevel@tonic-gate } 1409*7c478bd9Sstevel@tonic-gate results = kevp32; 1410*7c478bd9Sstevel@tonic-gate lev = NULL; /* start with first event in the queue */ 1411*7c478bd9Sstevel@tonic-gate for (nevents = 0; nevents < nmax; ) { 1412*7c478bd9Sstevel@tonic-gate pev = port_get_kevent(glist, lev); 1413*7c478bd9Sstevel@tonic-gate if (pev == NULL) /* no more events available */ 1414*7c478bd9Sstevel@tonic-gate break; 1415*7c478bd9Sstevel@tonic-gate if (pev->portkev_flags & PORT_KEV_FREE) { 1416*7c478bd9Sstevel@tonic-gate /* Just discard event */ 1417*7c478bd9Sstevel@tonic-gate list_remove(glist, pev); 1418*7c478bd9Sstevel@tonic-gate pev->portkev_flags &= ~(PORT_CLEANUP_DONE); 1419*7c478bd9Sstevel@tonic-gate if (PORT_FREE_EVENT(pev)) 1420*7c478bd9Sstevel@tonic-gate port_free_event_local(pev, 0); 1421*7c478bd9Sstevel@tonic-gate tnent--; 1422*7c478bd9Sstevel@tonic-gate continue; 1423*7c478bd9Sstevel@tonic-gate } 1424*7c478bd9Sstevel@tonic-gate 1425*7c478bd9Sstevel@tonic-gate /* move event data to copyout list */ 1426*7c478bd9Sstevel@tonic-gate if (port_copy_event32(&kevp32[nevents], pev, glist)) { 1427*7c478bd9Sstevel@tonic-gate /* 1428*7c478bd9Sstevel@tonic-gate * Event can not be delivered to the 1429*7c478bd9Sstevel@tonic-gate * current process. 1430*7c478bd9Sstevel@tonic-gate */ 1431*7c478bd9Sstevel@tonic-gate if (lev != NULL) 1432*7c478bd9Sstevel@tonic-gate list_insert_after(glist, lev, pev); 1433*7c478bd9Sstevel@tonic-gate else 1434*7c478bd9Sstevel@tonic-gate list_insert_head(glist, pev); 1435*7c478bd9Sstevel@tonic-gate lev = pev; /* last checked event */ 1436*7c478bd9Sstevel@tonic-gate } else { 1437*7c478bd9Sstevel@tonic-gate nevents++; /* # of events ready */ 1438*7c478bd9Sstevel@tonic-gate } 1439*7c478bd9Sstevel@tonic-gate } 1440*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1441*7c478bd9Sstevel@tonic-gate } 1442*7c478bd9Sstevel@tonic-gate 1443*7c478bd9Sstevel@tonic-gate /* 1444*7c478bd9Sstevel@tonic-gate * Remember number of remaining events in the temporary event queue. 1445*7c478bd9Sstevel@tonic-gate */ 1446*7c478bd9Sstevel@tonic-gate portq->portq_tnent = tnent - nevents; 1447*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_block_mutex); 1448*7c478bd9Sstevel@tonic-gate 1449*7c478bd9Sstevel@tonic-gate /* 1450*7c478bd9Sstevel@tonic-gate * Work to do before return : 1451*7c478bd9Sstevel@tonic-gate * - push list of remaining events back to the top of the standard 1452*7c478bd9Sstevel@tonic-gate * port queue. 1453*7c478bd9Sstevel@tonic-gate * - if this is the last thread calling port_get(n) then wakeup the 1454*7c478bd9Sstevel@tonic-gate * thread waiting on close(2). 1455*7c478bd9Sstevel@tonic-gate * - check for a deferred cv_signal from port_send_event() and wakeup 1456*7c478bd9Sstevel@tonic-gate * the sleeping thread. 1457*7c478bd9Sstevel@tonic-gate */ 1458*7c478bd9Sstevel@tonic-gate 1459*7c478bd9Sstevel@tonic-gate mutex_enter(&portq->portq_mutex); 1460*7c478bd9Sstevel@tonic-gate if (portq->portq_tnent) { 1461*7c478bd9Sstevel@tonic-gate /* 1462*7c478bd9Sstevel@tonic-gate * move remaining events in the temporary event queue back 1463*7c478bd9Sstevel@tonic-gate * to the port event queue 1464*7c478bd9Sstevel@tonic-gate */ 1465*7c478bd9Sstevel@tonic-gate port_push_eventq(portq); 1466*7c478bd9Sstevel@tonic-gate } 1467*7c478bd9Sstevel@tonic-gate portq->portq_getn--; /* update # of threads retrieving events */ 1468*7c478bd9Sstevel@tonic-gate if (--portq->portq_thrcnt == 0) { /* # of threads waiting ... */ 1469*7c478bd9Sstevel@tonic-gate /* Last thread => check close(2) conditions ... */ 1470*7c478bd9Sstevel@tonic-gate if (portq->portq_flags & PORTQ_CLOSE) { 1471*7c478bd9Sstevel@tonic-gate cv_signal(&portq->portq_closecv); 1472*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1473*7c478bd9Sstevel@tonic-gate kmem_free(results, eventsz * nmax); 1474*7c478bd9Sstevel@tonic-gate /* do not copyout events */ 1475*7c478bd9Sstevel@tonic-gate *nget = 0; 1476*7c478bd9Sstevel@tonic-gate return (EBADFD); 1477*7c478bd9Sstevel@tonic-gate } 1478*7c478bd9Sstevel@tonic-gate } else if (portq->portq_getn == 0) { 1479*7c478bd9Sstevel@tonic-gate /* 1480*7c478bd9Sstevel@tonic-gate * no other threads retrieving events ... 1481*7c478bd9Sstevel@tonic-gate * check wakeup conditions of sleeping threads 1482*7c478bd9Sstevel@tonic-gate */ 1483*7c478bd9Sstevel@tonic-gate if ((portq->portq_thread != NULL) && 1484*7c478bd9Sstevel@tonic-gate (portq->portq_nent >= portq->portq_nget)) 1485*7c478bd9Sstevel@tonic-gate cv_signal(&portq->portq_thread->portget_cv); 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate /* 1489*7c478bd9Sstevel@tonic-gate * Check PORTQ_POLLIN here because the current thread set temporarily 1490*7c478bd9Sstevel@tonic-gate * the number of events in the queue to zero. 1491*7c478bd9Sstevel@tonic-gate */ 1492*7c478bd9Sstevel@tonic-gate if (portq->portq_flags & PORTQ_POLLIN) { 1493*7c478bd9Sstevel@tonic-gate portq->portq_flags &= ~PORTQ_POLLIN; 1494*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1495*7c478bd9Sstevel@tonic-gate pollwakeup(&pp->port_pollhd, POLLIN); 1496*7c478bd9Sstevel@tonic-gate } else { 1497*7c478bd9Sstevel@tonic-gate mutex_exit(&portq->portq_mutex); 1498*7c478bd9Sstevel@tonic-gate } 1499*7c478bd9Sstevel@tonic-gate 1500*7c478bd9Sstevel@tonic-gate /* now copyout list of user event structures to user space */ 1501*7c478bd9Sstevel@tonic-gate if (nevents) { 1502*7c478bd9Sstevel@tonic-gate if (copyout(results, uevp, nevents * eventsz)) 1503*7c478bd9Sstevel@tonic-gate error = EFAULT; 1504*7c478bd9Sstevel@tonic-gate } 1505*7c478bd9Sstevel@tonic-gate kmem_free(results, eventsz * nmax); 1506*7c478bd9Sstevel@tonic-gate 1507*7c478bd9Sstevel@tonic-gate if (nevents == 0 && error == 0 && pgt->pgt_loop == 0 && blocking != 0) { 1508*7c478bd9Sstevel@tonic-gate /* no events retrieved: check loop conditions */ 1509*7c478bd9Sstevel@tonic-gate if (blocking == -1) { 1510*7c478bd9Sstevel@tonic-gate /* no timeout checked */ 1511*7c478bd9Sstevel@tonic-gate error = port_get_timeout(pgt->pgt_timeout, 1512*7c478bd9Sstevel@tonic-gate &pgt->pgt_rqtime, &rqtp, &blocking, flag); 1513*7c478bd9Sstevel@tonic-gate if (error) { 1514*7c478bd9Sstevel@tonic-gate *nget = nevents; 1515*7c478bd9Sstevel@tonic-gate return (error); 1516*7c478bd9Sstevel@tonic-gate } 1517*7c478bd9Sstevel@tonic-gate if (rqtp != NULL) { 1518*7c478bd9Sstevel@tonic-gate timespec_t now; 1519*7c478bd9Sstevel@tonic-gate pgt->pgt_timecheck = timechanged; 1520*7c478bd9Sstevel@tonic-gate gethrestime(&now); 1521*7c478bd9Sstevel@tonic-gate timespecadd(&pgt->pgt_rqtime, &now); 1522*7c478bd9Sstevel@tonic-gate } 1523*7c478bd9Sstevel@tonic-gate pgt->pgt_rqtp = rqtp; 1524*7c478bd9Sstevel@tonic-gate } else { 1525*7c478bd9Sstevel@tonic-gate /* timeout already checked -> remember values */ 1526*7c478bd9Sstevel@tonic-gate pgt->pgt_timecheck = timecheck; 1527*7c478bd9Sstevel@tonic-gate pgt->pgt_rqtime = *rqtp; 1528*7c478bd9Sstevel@tonic-gate pgt->pgt_rqtp = rqtp; 1529*7c478bd9Sstevel@tonic-gate } 1530*7c478bd9Sstevel@tonic-gate if (blocking) 1531*7c478bd9Sstevel@tonic-gate /* timeout remaining */ 1532*7c478bd9Sstevel@tonic-gate pgt->pgt_loop = 1; 1533*7c478bd9Sstevel@tonic-gate } 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate /* set number of user event structures completed */ 1536*7c478bd9Sstevel@tonic-gate *nget = nevents; 1537*7c478bd9Sstevel@tonic-gate return (error); 1538*7c478bd9Sstevel@tonic-gate } 1539*7c478bd9Sstevel@tonic-gate 1540*7c478bd9Sstevel@tonic-gate /* 1541*7c478bd9Sstevel@tonic-gate * 1. copy kernel event structure to user event structure. 1542*7c478bd9Sstevel@tonic-gate * 2. PORT_KEV_WIRED event structures will be reused by the "source" 1543*7c478bd9Sstevel@tonic-gate * 3. Remove PORT_KEV_DONEQ flag (event removed from the event queue) 1544*7c478bd9Sstevel@tonic-gate * 4. Other types of event structures can be delivered back to the port cache 1545*7c478bd9Sstevel@tonic-gate * (port_free_event_local()). 1546*7c478bd9Sstevel@tonic-gate * 5. The event source callback function is the last opportunity for the 1547*7c478bd9Sstevel@tonic-gate * event source to update events, to free local resources associated with 1548*7c478bd9Sstevel@tonic-gate * the event or to deny the delivery of the event. 1549*7c478bd9Sstevel@tonic-gate */ 1550*7c478bd9Sstevel@tonic-gate static int 1551*7c478bd9Sstevel@tonic-gate port_copy_event(port_event_t *puevp, port_kevent_t *pkevp, list_t *list) 1552*7c478bd9Sstevel@tonic-gate { 1553*7c478bd9Sstevel@tonic-gate int free_event = 0; 1554*7c478bd9Sstevel@tonic-gate int flags; 1555*7c478bd9Sstevel@tonic-gate int error; 1556*7c478bd9Sstevel@tonic-gate 1557*7c478bd9Sstevel@tonic-gate puevp->portev_source = pkevp->portkev_source; 1558*7c478bd9Sstevel@tonic-gate puevp->portev_object = pkevp->portkev_object; 1559*7c478bd9Sstevel@tonic-gate puevp->portev_user = pkevp->portkev_user; 1560*7c478bd9Sstevel@tonic-gate puevp->portev_events = pkevp->portkev_events; 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate /* remove event from the queue */ 1563*7c478bd9Sstevel@tonic-gate list_remove(list, pkevp); 1564*7c478bd9Sstevel@tonic-gate 1565*7c478bd9Sstevel@tonic-gate /* 1566*7c478bd9Sstevel@tonic-gate * Events of type PORT_KEV_WIRED remain allocated by the 1567*7c478bd9Sstevel@tonic-gate * event source. 1568*7c478bd9Sstevel@tonic-gate */ 1569*7c478bd9Sstevel@tonic-gate flags = pkevp->portkev_flags; 1570*7c478bd9Sstevel@tonic-gate if (pkevp->portkev_flags & PORT_KEV_WIRED) 1571*7c478bd9Sstevel@tonic-gate pkevp->portkev_flags &= ~PORT_KEV_DONEQ; 1572*7c478bd9Sstevel@tonic-gate else 1573*7c478bd9Sstevel@tonic-gate free_event = 1; 1574*7c478bd9Sstevel@tonic-gate 1575*7c478bd9Sstevel@tonic-gate if (pkevp->portkev_callback) { 1576*7c478bd9Sstevel@tonic-gate error = (*pkevp->portkev_callback)(pkevp->portkev_arg, 1577*7c478bd9Sstevel@tonic-gate &puevp->portev_events, pkevp->portkev_pid, 1578*7c478bd9Sstevel@tonic-gate PORT_CALLBACK_DEFAULT, pkevp); 1579*7c478bd9Sstevel@tonic-gate 1580*7c478bd9Sstevel@tonic-gate if (error) { 1581*7c478bd9Sstevel@tonic-gate /* 1582*7c478bd9Sstevel@tonic-gate * Event can not be delivered. 1583*7c478bd9Sstevel@tonic-gate * Caller must reinsert the event into the queue. 1584*7c478bd9Sstevel@tonic-gate */ 1585*7c478bd9Sstevel@tonic-gate pkevp->portkev_flags = flags; 1586*7c478bd9Sstevel@tonic-gate return (error); 1587*7c478bd9Sstevel@tonic-gate } 1588*7c478bd9Sstevel@tonic-gate } 1589*7c478bd9Sstevel@tonic-gate if (free_event) 1590*7c478bd9Sstevel@tonic-gate port_free_event_local(pkevp, 0); 1591*7c478bd9Sstevel@tonic-gate return (0); 1592*7c478bd9Sstevel@tonic-gate } 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1595*7c478bd9Sstevel@tonic-gate /* 1596*7c478bd9Sstevel@tonic-gate * 1. copy kernel event structure to user event structure. 1597*7c478bd9Sstevel@tonic-gate * 2. PORT_KEV_WIRED event structures will be reused by the "source" 1598*7c478bd9Sstevel@tonic-gate * 3. Remove PORT_KEV_DONEQ flag (event removed from the event queue) 1599*7c478bd9Sstevel@tonic-gate * 4. Other types of event structures can be delivered back to the port cache 1600*7c478bd9Sstevel@tonic-gate * (port_free_event_local()). 1601*7c478bd9Sstevel@tonic-gate * 5. The event source callback function is the last opportunity for the 1602*7c478bd9Sstevel@tonic-gate * event source to update events, to free local resources associated with 1603*7c478bd9Sstevel@tonic-gate * the event or to deny the delivery of the event. 1604*7c478bd9Sstevel@tonic-gate */ 1605*7c478bd9Sstevel@tonic-gate static int 1606*7c478bd9Sstevel@tonic-gate port_copy_event32(port_event32_t *puevp, port_kevent_t *pkevp, list_t *list) 1607*7c478bd9Sstevel@tonic-gate { 1608*7c478bd9Sstevel@tonic-gate int free_event = 0; 1609*7c478bd9Sstevel@tonic-gate int error; 1610*7c478bd9Sstevel@tonic-gate int flags; 1611*7c478bd9Sstevel@tonic-gate 1612*7c478bd9Sstevel@tonic-gate puevp->portev_source = pkevp->portkev_source; 1613*7c478bd9Sstevel@tonic-gate puevp->portev_object = (daddr32_t)pkevp->portkev_object; 1614*7c478bd9Sstevel@tonic-gate puevp->portev_user = (caddr32_t)(uintptr_t)pkevp->portkev_user; 1615*7c478bd9Sstevel@tonic-gate puevp->portev_events = pkevp->portkev_events; 1616*7c478bd9Sstevel@tonic-gate 1617*7c478bd9Sstevel@tonic-gate /* remove event from the queue */ 1618*7c478bd9Sstevel@tonic-gate list_remove(list, pkevp); 1619*7c478bd9Sstevel@tonic-gate 1620*7c478bd9Sstevel@tonic-gate /* 1621*7c478bd9Sstevel@tonic-gate * Events if type PORT_KEV_WIRED remain allocated by the 1622*7c478bd9Sstevel@tonic-gate * sub-system (source). 1623*7c478bd9Sstevel@tonic-gate */ 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate flags = pkevp->portkev_flags; 1626*7c478bd9Sstevel@tonic-gate if (pkevp->portkev_flags & PORT_KEV_WIRED) 1627*7c478bd9Sstevel@tonic-gate pkevp->portkev_flags &= ~PORT_KEV_DONEQ; 1628*7c478bd9Sstevel@tonic-gate else 1629*7c478bd9Sstevel@tonic-gate free_event = 1; 1630*7c478bd9Sstevel@tonic-gate 1631*7c478bd9Sstevel@tonic-gate if (pkevp->portkev_callback != NULL) { 1632*7c478bd9Sstevel@tonic-gate error = (*pkevp->portkev_callback)(pkevp->portkev_arg, 1633*7c478bd9Sstevel@tonic-gate &puevp->portev_events, pkevp->portkev_pid, 1634*7c478bd9Sstevel@tonic-gate PORT_CALLBACK_DEFAULT, pkevp); 1635*7c478bd9Sstevel@tonic-gate if (error) { 1636*7c478bd9Sstevel@tonic-gate /* 1637*7c478bd9Sstevel@tonic-gate * Event can not be delivered. 1638*7c478bd9Sstevel@tonic-gate * Caller must reinsert the event into the queue. 1639*7c478bd9Sstevel@tonic-gate */ 1640*7c478bd9Sstevel@tonic-gate pkevp->portkev_flags = flags; 1641*7c478bd9Sstevel@tonic-gate return (error); 1642*7c478bd9Sstevel@tonic-gate } 1643*7c478bd9Sstevel@tonic-gate } 1644*7c478bd9Sstevel@tonic-gate if (free_event) 1645*7c478bd9Sstevel@tonic-gate port_free_event_local(pkevp, 0); 1646*7c478bd9Sstevel@tonic-gate return (0); 1647*7c478bd9Sstevel@tonic-gate } 1648*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate /* 1651*7c478bd9Sstevel@tonic-gate * copyout alert event. 1652*7c478bd9Sstevel@tonic-gate */ 1653*7c478bd9Sstevel@tonic-gate static int 1654*7c478bd9Sstevel@tonic-gate port_get_alert(port_alert_t *pa, port_event_t *uevp) 1655*7c478bd9Sstevel@tonic-gate { 1656*7c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate /* copyout alert event structures to user space */ 1659*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 1660*7c478bd9Sstevel@tonic-gate port_event_t uev; 1661*7c478bd9Sstevel@tonic-gate uev.portev_source = PORT_SOURCE_ALERT; 1662*7c478bd9Sstevel@tonic-gate uev.portev_object = pa->portal_object; 1663*7c478bd9Sstevel@tonic-gate uev.portev_events = pa->portal_events; 1664*7c478bd9Sstevel@tonic-gate uev.portev_user = pa->portal_user; 1665*7c478bd9Sstevel@tonic-gate if (copyout(&uev, uevp, sizeof (port_event_t))) 1666*7c478bd9Sstevel@tonic-gate return (EFAULT); 1667*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1668*7c478bd9Sstevel@tonic-gate } else { 1669*7c478bd9Sstevel@tonic-gate port_event32_t uev32; 1670*7c478bd9Sstevel@tonic-gate uev32.portev_source = PORT_SOURCE_ALERT; 1671*7c478bd9Sstevel@tonic-gate uev32.portev_object = (daddr32_t)pa->portal_object; 1672*7c478bd9Sstevel@tonic-gate uev32.portev_events = pa->portal_events; 1673*7c478bd9Sstevel@tonic-gate uev32.portev_user = (daddr32_t)(uintptr_t)pa->portal_user; 1674*7c478bd9Sstevel@tonic-gate if (copyout(&uev32, uevp, sizeof (port_event32_t))) 1675*7c478bd9Sstevel@tonic-gate return (EFAULT); 1676*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1677*7c478bd9Sstevel@tonic-gate } 1678*7c478bd9Sstevel@tonic-gate return (0); 1679*7c478bd9Sstevel@tonic-gate } 1680*7c478bd9Sstevel@tonic-gate 1681*7c478bd9Sstevel@tonic-gate /* 1682*7c478bd9Sstevel@tonic-gate * Check return conditions : 1683*7c478bd9Sstevel@tonic-gate * - pending port close(2) 1684*7c478bd9Sstevel@tonic-gate * - threads waiting for events 1685*7c478bd9Sstevel@tonic-gate */ 1686*7c478bd9Sstevel@tonic-gate static void 1687*7c478bd9Sstevel@tonic-gate port_check_return_cond(port_queue_t *portq) 1688*7c478bd9Sstevel@tonic-gate { 1689*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&portq->portq_mutex)); 1690*7c478bd9Sstevel@tonic-gate portq->portq_thrcnt--; 1691*7c478bd9Sstevel@tonic-gate if (portq->portq_flags & PORTQ_CLOSE) { 1692*7c478bd9Sstevel@tonic-gate if (portq->portq_thrcnt == 0) 1693*7c478bd9Sstevel@tonic-gate cv_signal(&portq->portq_closecv); 1694*7c478bd9Sstevel@tonic-gate else 1695*7c478bd9Sstevel@tonic-gate cv_signal(&portq->portq_thread->portget_cv); 1696*7c478bd9Sstevel@tonic-gate } 1697*7c478bd9Sstevel@tonic-gate } 1698*7c478bd9Sstevel@tonic-gate 1699*7c478bd9Sstevel@tonic-gate /* 1700*7c478bd9Sstevel@tonic-gate * The port_get_kevent() function returns 1701*7c478bd9Sstevel@tonic-gate * - the event located at the head of the queue if 'last' pointer is NULL 1702*7c478bd9Sstevel@tonic-gate * - the next event after the event pointed by 'last' 1703*7c478bd9Sstevel@tonic-gate * The caller of this function is responsible for the integrity of the queue 1704*7c478bd9Sstevel@tonic-gate * in use: 1705*7c478bd9Sstevel@tonic-gate * - port_getn() is using a temporary queue protected with 1706*7c478bd9Sstevel@tonic-gate * portq->portq_block_mutex 1707*7c478bd9Sstevel@tonic-gate * - port_close_events() is working on the global event queue and protects the 1708*7c478bd9Sstevel@tonic-gate * queue with portq->portq_mutex. 1709*7c478bd9Sstevel@tonic-gate */ 1710*7c478bd9Sstevel@tonic-gate 1711*7c478bd9Sstevel@tonic-gate port_kevent_t * 1712*7c478bd9Sstevel@tonic-gate port_get_kevent(list_t *list, port_kevent_t *last) 1713*7c478bd9Sstevel@tonic-gate { 1714*7c478bd9Sstevel@tonic-gate if (last == NULL) 1715*7c478bd9Sstevel@tonic-gate return (list_head(list)); 1716*7c478bd9Sstevel@tonic-gate else 1717*7c478bd9Sstevel@tonic-gate return (list_next(list, last)); 1718*7c478bd9Sstevel@tonic-gate } 1719*7c478bd9Sstevel@tonic-gate 1720*7c478bd9Sstevel@tonic-gate /* 1721*7c478bd9Sstevel@tonic-gate * The port_get_timeout() function gets the timeout data from user space 1722*7c478bd9Sstevel@tonic-gate * and converts that info into a corresponding internal representation. 1723*7c478bd9Sstevel@tonic-gate * The kerneldata flag means that the timeout data is already loaded. 1724*7c478bd9Sstevel@tonic-gate */ 1725*7c478bd9Sstevel@tonic-gate static int 1726*7c478bd9Sstevel@tonic-gate port_get_timeout(timespec_t *timeout, timespec_t *rqtime, timespec_t **rqtp, 1727*7c478bd9Sstevel@tonic-gate int *blocking, int kerneldata) 1728*7c478bd9Sstevel@tonic-gate { 1729*7c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 1730*7c478bd9Sstevel@tonic-gate 1731*7c478bd9Sstevel@tonic-gate *rqtp = NULL; 1732*7c478bd9Sstevel@tonic-gate if (timeout == NULL) { 1733*7c478bd9Sstevel@tonic-gate *blocking = 1; 1734*7c478bd9Sstevel@tonic-gate return (0); 1735*7c478bd9Sstevel@tonic-gate } 1736*7c478bd9Sstevel@tonic-gate 1737*7c478bd9Sstevel@tonic-gate if (kerneldata) { 1738*7c478bd9Sstevel@tonic-gate *rqtime = *timeout; 1739*7c478bd9Sstevel@tonic-gate } else { 1740*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 1741*7c478bd9Sstevel@tonic-gate if (copyin(timeout, rqtime, sizeof (*rqtime))) 1742*7c478bd9Sstevel@tonic-gate return (EFAULT); 1743*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1744*7c478bd9Sstevel@tonic-gate } else { 1745*7c478bd9Sstevel@tonic-gate timespec32_t wait_time_32; 1746*7c478bd9Sstevel@tonic-gate if (copyin(timeout, &wait_time_32, 1747*7c478bd9Sstevel@tonic-gate sizeof (wait_time_32))) 1748*7c478bd9Sstevel@tonic-gate return (EFAULT); 1749*7c478bd9Sstevel@tonic-gate TIMESPEC32_TO_TIMESPEC(rqtime, &wait_time_32); 1750*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1751*7c478bd9Sstevel@tonic-gate } 1752*7c478bd9Sstevel@tonic-gate } 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate if (rqtime->tv_sec == 0 && rqtime->tv_nsec == 0) { 1755*7c478bd9Sstevel@tonic-gate *blocking = 0; 1756*7c478bd9Sstevel@tonic-gate return (0); 1757*7c478bd9Sstevel@tonic-gate } 1758*7c478bd9Sstevel@tonic-gate 1759*7c478bd9Sstevel@tonic-gate if (rqtime->tv_sec < 0 || 1760*7c478bd9Sstevel@tonic-gate rqtime->tv_nsec < 0 || rqtime->tv_nsec >= NANOSEC) 1761*7c478bd9Sstevel@tonic-gate return (EINVAL); 1762*7c478bd9Sstevel@tonic-gate 1763*7c478bd9Sstevel@tonic-gate *rqtp = rqtime; 1764*7c478bd9Sstevel@tonic-gate *blocking = 1; 1765*7c478bd9Sstevel@tonic-gate return (0); 1766*7c478bd9Sstevel@tonic-gate } 1767*7c478bd9Sstevel@tonic-gate 1768*7c478bd9Sstevel@tonic-gate /* 1769*7c478bd9Sstevel@tonic-gate * port_queue_thread() 1770*7c478bd9Sstevel@tonic-gate * Threads requiring more events than available will be put in a wait queue. 1771*7c478bd9Sstevel@tonic-gate * There is a "thread wait queue" per port. 1772*7c478bd9Sstevel@tonic-gate * Threads requiring less events get a higher priority than others and they 1773*7c478bd9Sstevel@tonic-gate * will be awoken first. 1774*7c478bd9Sstevel@tonic-gate */ 1775*7c478bd9Sstevel@tonic-gate static portget_t * 1776*7c478bd9Sstevel@tonic-gate port_queue_thread(port_queue_t *portq, uint_t nget) 1777*7c478bd9Sstevel@tonic-gate { 1778*7c478bd9Sstevel@tonic-gate portget_t *pgetp; 1779*7c478bd9Sstevel@tonic-gate portget_t *ttp; 1780*7c478bd9Sstevel@tonic-gate portget_t *htp; 1781*7c478bd9Sstevel@tonic-gate 1782*7c478bd9Sstevel@tonic-gate pgetp = kmem_zalloc(sizeof (portget_t), KM_SLEEP); 1783*7c478bd9Sstevel@tonic-gate pgetp->portget_nget = nget; 1784*7c478bd9Sstevel@tonic-gate pgetp->portget_pid = curproc->p_pid; 1785*7c478bd9Sstevel@tonic-gate if (portq->portq_thread == NULL) { 1786*7c478bd9Sstevel@tonic-gate /* first waiting thread */ 1787*7c478bd9Sstevel@tonic-gate portq->portq_thread = pgetp; 1788*7c478bd9Sstevel@tonic-gate portq->portq_nget = nget; 1789*7c478bd9Sstevel@tonic-gate pgetp->portget_prev = pgetp; 1790*7c478bd9Sstevel@tonic-gate pgetp->portget_next = pgetp; 1791*7c478bd9Sstevel@tonic-gate return (pgetp); 1792*7c478bd9Sstevel@tonic-gate } 1793*7c478bd9Sstevel@tonic-gate 1794*7c478bd9Sstevel@tonic-gate /* 1795*7c478bd9Sstevel@tonic-gate * thread waiting for less events will be set on top of the queue. 1796*7c478bd9Sstevel@tonic-gate */ 1797*7c478bd9Sstevel@tonic-gate ttp = portq->portq_thread; 1798*7c478bd9Sstevel@tonic-gate htp = ttp; 1799*7c478bd9Sstevel@tonic-gate for (;;) { 1800*7c478bd9Sstevel@tonic-gate if (nget <= ttp->portget_nget) 1801*7c478bd9Sstevel@tonic-gate break; 1802*7c478bd9Sstevel@tonic-gate if (htp == ttp->portget_next) 1803*7c478bd9Sstevel@tonic-gate break; /* last event */ 1804*7c478bd9Sstevel@tonic-gate ttp = ttp->portget_next; 1805*7c478bd9Sstevel@tonic-gate } 1806*7c478bd9Sstevel@tonic-gate 1807*7c478bd9Sstevel@tonic-gate /* add thread to the queue */ 1808*7c478bd9Sstevel@tonic-gate pgetp->portget_next = ttp; 1809*7c478bd9Sstevel@tonic-gate pgetp->portget_prev = ttp->portget_prev; 1810*7c478bd9Sstevel@tonic-gate ttp->portget_prev->portget_next = pgetp; 1811*7c478bd9Sstevel@tonic-gate ttp->portget_prev = pgetp; 1812*7c478bd9Sstevel@tonic-gate if (portq->portq_thread == ttp) 1813*7c478bd9Sstevel@tonic-gate portq->portq_thread = pgetp; 1814*7c478bd9Sstevel@tonic-gate portq->portq_nget = portq->portq_thread->portget_nget; 1815*7c478bd9Sstevel@tonic-gate return (pgetp); 1816*7c478bd9Sstevel@tonic-gate } 1817*7c478bd9Sstevel@tonic-gate 1818*7c478bd9Sstevel@tonic-gate /* 1819*7c478bd9Sstevel@tonic-gate * Take thread out of the queue. 1820*7c478bd9Sstevel@tonic-gate */ 1821*7c478bd9Sstevel@tonic-gate static void 1822*7c478bd9Sstevel@tonic-gate port_dequeue_thread(port_queue_t *portq, portget_t *pgetp) 1823*7c478bd9Sstevel@tonic-gate { 1824*7c478bd9Sstevel@tonic-gate if (pgetp->portget_next == pgetp) { 1825*7c478bd9Sstevel@tonic-gate /* last (single) waiting thread */ 1826*7c478bd9Sstevel@tonic-gate portq->portq_thread = NULL; 1827*7c478bd9Sstevel@tonic-gate } else { 1828*7c478bd9Sstevel@tonic-gate pgetp->portget_prev->portget_next = pgetp->portget_next; 1829*7c478bd9Sstevel@tonic-gate pgetp->portget_next->portget_prev = pgetp->portget_prev; 1830*7c478bd9Sstevel@tonic-gate if (portq->portq_thread == pgetp) 1831*7c478bd9Sstevel@tonic-gate portq->portq_thread = pgetp->portget_next; 1832*7c478bd9Sstevel@tonic-gate portq->portq_nget = portq->portq_thread->portget_nget; 1833*7c478bd9Sstevel@tonic-gate } 1834*7c478bd9Sstevel@tonic-gate kmem_free(pgetp, sizeof (portget_t)); 1835*7c478bd9Sstevel@tonic-gate } 1836*7c478bd9Sstevel@tonic-gate 1837*7c478bd9Sstevel@tonic-gate /* 1838*7c478bd9Sstevel@tonic-gate * Set up event port kstats. 1839*7c478bd9Sstevel@tonic-gate */ 1840*7c478bd9Sstevel@tonic-gate static void 1841*7c478bd9Sstevel@tonic-gate port_kstat_init() 1842*7c478bd9Sstevel@tonic-gate { 1843*7c478bd9Sstevel@tonic-gate kstat_t *ksp; 1844*7c478bd9Sstevel@tonic-gate uint_t ndata; 1845*7c478bd9Sstevel@tonic-gate 1846*7c478bd9Sstevel@tonic-gate ndata = sizeof (port_kstat) / sizeof (kstat_named_t); 1847*7c478bd9Sstevel@tonic-gate ksp = kstat_create("portfs", 0, "Event Ports", "misc", 1848*7c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, ndata, KSTAT_FLAG_VIRTUAL); 1849*7c478bd9Sstevel@tonic-gate if (ksp) { 1850*7c478bd9Sstevel@tonic-gate ksp->ks_data = &port_kstat; 1851*7c478bd9Sstevel@tonic-gate kstat_install(ksp); 1852*7c478bd9Sstevel@tonic-gate } 1853*7c478bd9Sstevel@tonic-gate } 1854