|  | /* | 
|  | * Server-side pipe management | 
|  | * | 
|  | * Copyright (C) 1998 Alexandre Julliard | 
|  | */ | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <fcntl.h> | 
|  | #include <string.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <sys/errno.h> | 
|  | #include <sys/stat.h> | 
|  | #include <sys/time.h> | 
|  | #include <sys/types.h> | 
|  | #include <time.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | #include "winerror.h" | 
|  | #include "winbase.h" | 
|  | #include "server/thread.h" | 
|  |  | 
|  | enum side { READ_SIDE, WRITE_SIDE }; | 
|  |  | 
|  | struct pipe | 
|  | { | 
|  | struct object obj;             /* object header */ | 
|  | struct pipe  *other;           /* the pipe other end */ | 
|  | int           fd;              /* Unix file descriptor */ | 
|  | enum side     side;            /* which side of the pipe is this */ | 
|  | }; | 
|  |  | 
|  | static void pipe_dump( struct object *obj, int verbose ); | 
|  | static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry ); | 
|  | static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entry ); | 
|  | static int pipe_signaled( struct object *obj, struct thread *thread ); | 
|  | static int pipe_get_read_fd( struct object *obj ); | 
|  | static int pipe_get_write_fd( struct object *obj ); | 
|  | static int pipe_get_info( struct object *obj, struct get_file_info_reply *reply ); | 
|  | static void pipe_destroy( struct object *obj ); | 
|  |  | 
|  | static const struct object_ops pipe_ops = | 
|  | { | 
|  | pipe_dump, | 
|  | pipe_add_queue, | 
|  | pipe_remove_queue, | 
|  | pipe_signaled, | 
|  | no_satisfied, | 
|  | pipe_get_read_fd, | 
|  | pipe_get_write_fd, | 
|  | no_flush, | 
|  | pipe_get_info, | 
|  | pipe_destroy | 
|  | }; | 
|  |  | 
|  | static const struct select_ops select_ops = | 
|  | { | 
|  | default_select_event, | 
|  | NULL   /* we never set a timeout on a pipe */ | 
|  | }; | 
|  |  | 
|  | int create_pipe( struct object *obj[2] ) | 
|  | { | 
|  | struct pipe *newpipe[2]; | 
|  | int fd[2]; | 
|  |  | 
|  | if (pipe( fd ) == -1) | 
|  | { | 
|  | file_set_error(); | 
|  | return 0; | 
|  | } | 
|  | if (!(newpipe[0] = mem_alloc( sizeof(struct pipe) ))) | 
|  | { | 
|  | close( fd[0] ); | 
|  | close( fd[1] ); | 
|  | return 0; | 
|  | } | 
|  | if (!(newpipe[1] = mem_alloc( sizeof(struct pipe) ))) | 
|  | { | 
|  | close( fd[0] ); | 
|  | close( fd[1] ); | 
|  | free( newpipe[0] ); | 
|  | return 0; | 
|  | } | 
|  | init_object( &newpipe[0]->obj, &pipe_ops, NULL ); | 
|  | init_object( &newpipe[1]->obj, &pipe_ops, NULL ); | 
|  | newpipe[0]->fd    = fd[0]; | 
|  | newpipe[0]->other = newpipe[1]; | 
|  | newpipe[0]->side  = READ_SIDE; | 
|  | newpipe[1]->fd    = fd[1]; | 
|  | newpipe[1]->other = newpipe[0]; | 
|  | newpipe[1]->side  = WRITE_SIDE; | 
|  | obj[0] = &newpipe[0]->obj; | 
|  | obj[1] = &newpipe[1]->obj; | 
|  | CLEAR_ERROR(); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static void pipe_dump( struct object *obj, int verbose ) | 
|  | { | 
|  | struct pipe *pipe = (struct pipe *)obj; | 
|  | assert( obj->ops == &pipe_ops ); | 
|  | fprintf( stderr, "Pipe %s-side fd=%d\n", | 
|  | (pipe->side == READ_SIDE) ? "read" : "write", pipe->fd ); | 
|  | } | 
|  |  | 
|  | static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry ) | 
|  | { | 
|  | struct pipe *pipe = (struct pipe *)obj; | 
|  | assert( obj->ops == &pipe_ops ); | 
|  | if (!obj->head)  /* first on the queue */ | 
|  | { | 
|  | if (!add_select_user( pipe->fd, | 
|  | (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT, | 
|  | &select_ops, pipe )) | 
|  | { | 
|  | SET_ERROR( ERROR_OUTOFMEMORY ); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | add_queue( obj, entry ); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entry ) | 
|  | { | 
|  | struct pipe *pipe = (struct pipe *)grab_object(obj); | 
|  | assert( obj->ops == &pipe_ops ); | 
|  |  | 
|  | remove_queue( obj, entry ); | 
|  | if (!obj->head)  /* last on the queue is gone */ | 
|  | remove_select_user( pipe->fd ); | 
|  | release_object( obj ); | 
|  | } | 
|  |  | 
|  | static int pipe_signaled( struct object *obj, struct thread *thread ) | 
|  | { | 
|  | struct pipe *pipe = (struct pipe *)obj; | 
|  | struct timeval tv = { 0, 0 }; | 
|  | fd_set fds; | 
|  |  | 
|  | assert( obj->ops == &pipe_ops ); | 
|  | FD_ZERO( &fds ); | 
|  | FD_SET( pipe->fd, &fds ); | 
|  | if (pipe->side == READ_SIDE) | 
|  | return select( pipe->fd + 1, &fds, NULL, NULL, &tv ) > 0; | 
|  | else | 
|  | return select( pipe->fd + 1, NULL, &fds, NULL, &tv ) > 0; | 
|  | } | 
|  |  | 
|  | static int pipe_get_read_fd( struct object *obj ) | 
|  | { | 
|  | struct pipe *pipe = (struct pipe *)obj; | 
|  | assert( obj->ops == &pipe_ops ); | 
|  |  | 
|  | if (!pipe->other) | 
|  | { | 
|  | SET_ERROR( ERROR_BROKEN_PIPE ); | 
|  | return -1; | 
|  | } | 
|  | if (pipe->side != READ_SIDE)  /* FIXME: should not be necessary */ | 
|  | { | 
|  | SET_ERROR( ERROR_ACCESS_DENIED ); | 
|  | return -1; | 
|  | } | 
|  | return dup( pipe->fd ); | 
|  | } | 
|  |  | 
|  | static int pipe_get_write_fd( struct object *obj ) | 
|  | { | 
|  | struct pipe *pipe = (struct pipe *)obj; | 
|  | assert( obj->ops == &pipe_ops ); | 
|  |  | 
|  | if (!pipe->other) | 
|  | { | 
|  | SET_ERROR( ERROR_BROKEN_PIPE ); | 
|  | return -1; | 
|  | } | 
|  | if (pipe->side != WRITE_SIDE)  /* FIXME: should not be necessary */ | 
|  | { | 
|  | SET_ERROR( ERROR_ACCESS_DENIED ); | 
|  | return -1; | 
|  | } | 
|  | return dup( pipe->fd ); | 
|  | } | 
|  |  | 
|  | static int pipe_get_info( struct object *obj, struct get_file_info_reply *reply ) | 
|  | { | 
|  | memset( reply, 0, sizeof(*reply) ); | 
|  | reply->type = FILE_TYPE_PIPE; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static void pipe_destroy( struct object *obj ) | 
|  | { | 
|  | struct pipe *pipe = (struct pipe *)obj; | 
|  | assert( obj->ops == &pipe_ops ); | 
|  |  | 
|  | if (pipe->other) pipe->other->other = NULL; | 
|  | close( pipe->fd ); | 
|  | free( pipe ); | 
|  | } |