port_fd.c revision 3470957343f37ed9baa957980891dbbe4c2d7092
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/poll_impl.h>
#include <sys/port_impl.h>
/* local functions */
static int port_fd_callback(void *, int *, pid_t, int, void *);
static void port_close_sourcefd(void *, int, pid_t, int);
/*
* port_fd_callback()
* The event port framework uses callback functions to notify associated
* event sources about actions on source specific objects.
* The source itself defines the "arg" required to identify the object with
* events. In the port_fd_callback() case the "arg" is a pointer to portfd_t
* structure. The portfd_t structure is specific for PORT_SOURCE_FD source.
* The port_fd_callback() function is notified in three cases:
* - PORT_CALLBACK_DEFAULT
* The object (fd) will be delivered to the application.
* - PORT_CALLBACK_DISSOCIATE
* The object (fd) will be dissociated from the port.
* - PORT_CALLBACK_CLOSE
* The object (fd) will be dissociated from the port because the port
* is being closed.
* A fd is shareable between processes only when
* - processes have the same fd id and
* - processes have the same fp.
* A fd becomes shareable:
* - on fork() across parent and child process and
* - when I_SENDFD is used to pass file descriptors between parent and child
* immediately after fork() (the sender and receiver must get the same
* file descriptor id).
* If a fd is shared between processes, all involved processes will get
* the same rights related to re-association of the fd with the port and
* retrieve of events from that fd.
* The process which associated the fd with a port for the first time
* becomes also the owner of the association. Only the owner of the
* association is allowed to dissociate the fd from the port.
*/
/* ARGSUSED */
static int
{
int error;
switch (flag) {
case PORT_CALLBACK_DEFAULT:
/*
* Check if current process is allowed to retrieve
* events from this fd.
*/
break;
}
break;
}
}
error = 0;
break;
case PORT_CALLBACK_DISSOCIATE:
error = 0;
break;
case PORT_CALLBACK_CLOSE:
}
error = 0;
break;
default:
break;
}
return (error);
}
/*
* This routine returns a pointer to a cached poll fd entry, or NULL if it
* does not find it in the hash table.
* The fd is used as index.
* The fd and the fp are used to detect a valid entry.
* This function returns a pointer to a valid portfd_t structure only when
* the fd and the fp in the args match the entries in polldat_t.
*/
portfd_t *
{
break;
}
}
/*
* port_associate_fd()
* This function associates new file descriptors with a port or
* reactivate already associated file descriptors.
* The reactivation also updates the events types to be checked and the
* attached user pointer.
* Per port a cache is used to store associated file descriptors.
* Internally the VOP_POLL interface is used to poll for existing events.
* The VOP_POLL interface can also deliver a pointer to a pollhead_t structure
* which is used to enqueue polldat_t structures with pending events.
* If VOP_POLL immediately returns valid events (revents) then those events
* will be submitted to the event port with port_send_event().
* Otherwise VOP_POLL does not return events but it delivers a pointer to a
* pollhead_t structure. In such a case the corresponding file system behind
* VOP_POLL will use the pollwakeup() function to notify about exisiting
* events.
*/
int
void *user)
{
int fd;
short revents;
int error = 0;
return (EBADFD);
return (EBADFD);
/*
* This is the first time that a fd is being associated with
* the current port:
* - create PORT_SOURCE_FD cache
* - associate PORT_SOURCE_FD source with the port
*/
if (error) {
return (error);
}
/* create polldat cache */
} else {
}
/*
* new entry
* Allocate a polldat_t structure per fd
* The use of the polldat_t structure to cache file descriptors
* is required to be able to share the pollwakeup() function
* with poll(2) and devpoll(7d).
*/
/* Allocate a port event structure per fd */
if (error) {
return (error);
}
/* add portfd_t entry to the cache */
/*
* Add current port to the file descriptor interested list
* The members of the list are notified when the file descriptor
* is closed.
*/
} else {
/*
* The file descriptor is already associated with the port
*/
/*
* Check if the re-association happens before the last
* submitted event of the file descriptor was retrieved.
* Clear the PORT_KEV_VALID flag if set. No new events
* should get submitted after this flag is cleared.
*/
}
/*
* Remove any events that where already fired
* for this fd and are still in the port queue.
*/
} else {
}
}
/*
* allow new events.
*/
/*
* do VOP_POLL and cache this poll fd.
*
* XXX - pollrelock() logic needs to know
* which pollcache lock to grab. It'd be a
* cleaner solution if we could pass pcp as
* an arguement in VOP_POLL interface instead
* of implicitly passing it using thread_t
* struct. On the other hand, changing VOP_POLL
* poll routine to change.
*/
/*
* To keep synchronization between VOP_POLL above and
* pollhead_insert below, it is necessary to
* call VOP_POLL() again (see port_bind_pollhead()).
*/
if (error) {
/* dissociate the fd from the port */
return (error);
}
/*
* No events delivered yet.
* Bind pollhead pointer with current polldat_t structure.
* Sub-system will call pollwakeup() later with php as
* argument.
*/
if (error) {
return (error);
}
}
/*
* Check if new events where detected and no events have been
* delivered. The revents was already set after the VOP_POLL
* above or it was updated in port_bind_pollhead().
*/
/* send events to the event port */
/*
* port_send_event will release the portkev_lock mutex.
*/
} else {
}
return (error);
}
/*
* The port_dissociate_fd() function dissociates the delivered file
* descriptor from the event port and removes already fired events.
* If a fd is shared between processes, all involved processes will get
* the same rights related to re-association of the fd with the port and
* retrieve of events from that fd.
* The process which associated the fd with a port for the first time
* becomes also the owner of the association. Only the owner of the
* association is allowed to dissociate the fd from the port.
*/
int
{
int fd;
return (EBADFD);
/* no file descriptor cache available */
return (0);
}
return (EBADFD);
}
return (0);
}
/* only association owner is allowed to remove the association */
return (EACCES);
}
/* remove port from the file descriptor interested list */
/* remove polldat & port event structure */
return (0);
}
/*
* Remove the fd from the event port cache.
*/
static void
{
}
/* remove polldat struct */
}
/*
* Associate event port polldat_t structure with sub-system pointer to
* a polhead_t structure.
*/
static int
{
int error;
/*
* During re-association of a fd with a port the pd_php pointer
* is still the same as at the first association time.
*/
return (0); /* already associated */
/* polldat_t associated with another pollhead_t pointer */
/*
* Before pollhead_insert() pollwakeup() will not detect a polldat
* entry in the ph_list and the event notification will disappear.
* This happens because polldat_t is still not associated with
* the pointer to the pollhead_t structure.
*/
/*
* From now on event notification can be detected in pollwakeup(),
* Use VOP_POLL() again to check the current status of the event.
*/
return (error);
}
/*
* Grow the hash table. Rehash all the elements on the hash table.
*/
static void
{
int oldsize;
int i;
KM_SLEEP);
/*
* rehash existing elements
*/
pcp->pc_fdcount = 0;
for (i = 0; i < oldsize; i++) {
}
}
}
/*
* This routine inserts a polldat into the portcache's hash table. It
* may be necessary to grow the size of the hash table.
*/
static void
{
pcp->pc_fdcount++;
}
/*
* The port_remove_portfd() function dissociates the port from the fd
* and vive versa.
*/
static void
{
/*
* If we did not get the fp for pd_fd but its portfd_t
* still exist in the cache, it means the pd_fd is being
* closed by some other thread which will also free the portfd_t.
*/
}
}
/*
* This function is used by port_close_sourcefd() to destroy the cache
* on last close.
*/
static void
{
}
/*
* port_close() calls this function to request the PORT_SOURCE_FD source
*/
/* ARGSUSED */
static void
{
int index;
/* no cache available -> nothing to do */
return;
/*
* Scan the cache and free all allocated portfd_t and port_kevent_t
* structures.
*/
/*
* remove polldat + port_event_t from cache
* only when current process did the
* association.
*/
}
}
}
if (lastclose) {
/*
* Wait for all the portfd's to be freed.
* The remaining portfd_t's are the once we did not
* free in port_remove_portfd since some other thread
* is closing the fd. These threads will free the portfd_t's
* once we drop the pc_lock mutex.
*/
while (pcp->pc_fdcount) {
}
/* event port vnode will be destroyed -> remove everything */
}
/*
* last close:
* pollwakeup() can not further interact with this cache
* (all polldat structs are removed from pollhead entries).
*/
if (lastclose)
}