Fixed refcount handling (waiting clients must not increase the
refcount of the pipe). Converted linked lists to use the standard functions. Small cleanups.
This commit is contained in:
parent
52e5ac5e41
commit
7c1cf8f009
|
@ -49,7 +49,6 @@
|
||||||
|
|
||||||
enum pipe_state
|
enum pipe_state
|
||||||
{
|
{
|
||||||
ps_none,
|
|
||||||
ps_idle_server,
|
ps_idle_server,
|
||||||
ps_wait_open,
|
ps_wait_open,
|
||||||
ps_connected_server,
|
ps_connected_server,
|
||||||
|
@ -69,13 +68,12 @@ struct named_pipe;
|
||||||
|
|
||||||
struct pipe_server
|
struct pipe_server
|
||||||
{
|
{
|
||||||
struct object obj;
|
struct object obj; /* object header */
|
||||||
struct fd *fd;
|
struct fd *fd; /* pipe file descriptor */
|
||||||
enum pipe_state state;
|
struct list entry; /* entry in named pipe servers list */
|
||||||
struct pipe_client *client;
|
enum pipe_state state; /* server state */
|
||||||
|
struct pipe_client *client; /* client that this server is connected to */
|
||||||
struct named_pipe *pipe;
|
struct named_pipe *pipe;
|
||||||
struct pipe_server *next;
|
|
||||||
struct pipe_server *prev;
|
|
||||||
struct timeout_user *flush_poll;
|
struct timeout_user *flush_poll;
|
||||||
struct event *event;
|
struct event *event;
|
||||||
struct wait_info wait;
|
struct wait_info wait;
|
||||||
|
@ -83,16 +81,16 @@ struct pipe_server
|
||||||
|
|
||||||
struct pipe_client
|
struct pipe_client
|
||||||
{
|
{
|
||||||
struct object obj;
|
struct object obj; /* object header */
|
||||||
struct fd *fd;
|
struct fd *fd; /* pipe file descriptor */
|
||||||
struct pipe_server *server;
|
struct pipe_server *server; /* server that this client is connected to */
|
||||||
struct wait_info wait;
|
struct wait_info wait;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct connect_wait
|
struct connect_wait
|
||||||
{
|
{
|
||||||
|
struct list entry; /* entry in named pipe wait list */
|
||||||
struct wait_info wait;
|
struct wait_info wait;
|
||||||
struct connect_wait *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct named_pipe
|
struct named_pipe
|
||||||
|
@ -104,8 +102,8 @@ struct named_pipe
|
||||||
unsigned int insize;
|
unsigned int insize;
|
||||||
unsigned int timeout;
|
unsigned int timeout;
|
||||||
unsigned int instances;
|
unsigned int instances;
|
||||||
struct pipe_server *servers;
|
struct list servers; /* list of servers using this pipe */
|
||||||
struct connect_wait *connect_waiters;
|
struct list waiters; /* list of clients waiting to connect */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void named_pipe_dump( struct object *obj, int verbose );
|
static void named_pipe_dump( struct object *obj, int verbose );
|
||||||
|
@ -187,30 +185,23 @@ static void named_pipe_dump( struct object *obj, int verbose )
|
||||||
{
|
{
|
||||||
struct named_pipe *pipe = (struct named_pipe *) obj;
|
struct named_pipe *pipe = (struct named_pipe *) obj;
|
||||||
assert( obj->ops == &named_pipe_ops );
|
assert( obj->ops == &named_pipe_ops );
|
||||||
fprintf( stderr, "named pipe %p\n" ,pipe);
|
fprintf( stderr, "Named pipe " );
|
||||||
|
dump_object_name( &pipe->obj );
|
||||||
|
fprintf( stderr, "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pipe_server_dump( struct object *obj, int verbose )
|
static void pipe_server_dump( struct object *obj, int verbose )
|
||||||
{
|
{
|
||||||
struct pipe_server *server = (struct pipe_server *) obj;
|
struct pipe_server *server = (struct pipe_server *) obj;
|
||||||
assert( obj->ops == &pipe_server_ops );
|
assert( obj->ops == &pipe_server_ops );
|
||||||
fprintf( stderr, "named pipe server %p (state %d)\n",
|
fprintf( stderr, "Named pipe server pipe=%p state=%d\n", server->pipe, server->state );
|
||||||
server, server->state );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pipe_client_dump( struct object *obj, int verbose )
|
static void pipe_client_dump( struct object *obj, int verbose )
|
||||||
{
|
{
|
||||||
struct pipe_client *client = (struct pipe_client *) obj;
|
struct pipe_client *client = (struct pipe_client *) obj;
|
||||||
assert( obj->ops == &pipe_server_ops );
|
assert( obj->ops == &pipe_client_ops );
|
||||||
fprintf( stderr, "named pipe client %p (server state %d)\n",
|
fprintf( stderr, "Named pipe client server=%p\n", client->server );
|
||||||
client, client->server->state );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void named_pipe_destroy( struct object *obj)
|
|
||||||
{
|
|
||||||
struct named_pipe *pipe = (struct named_pipe *) obj;
|
|
||||||
assert( !pipe->servers );
|
|
||||||
assert( !pipe->instances );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notify_waiter( struct wait_info *wait, unsigned int status )
|
static void notify_waiter( struct wait_info *wait, unsigned int status )
|
||||||
|
@ -232,22 +223,29 @@ static void set_waiter( struct wait_info *wait, void *func, void *ov )
|
||||||
wait->overlapped = ov;
|
wait->overlapped = ov;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notify_connect_waiters( struct named_pipe *pipe )
|
static void notify_connect_waiters( struct named_pipe *pipe, unsigned int status )
|
||||||
{
|
{
|
||||||
struct connect_wait *cw, **x = &pipe->connect_waiters;
|
struct list *ptr;
|
||||||
|
|
||||||
while( *x )
|
while ((ptr = list_head( &pipe->waiters )) != NULL)
|
||||||
{
|
{
|
||||||
cw = *x;
|
struct connect_wait *waiter = LIST_ENTRY( ptr, struct connect_wait, entry );
|
||||||
notify_waiter( &cw->wait, STATUS_SUCCESS );
|
notify_waiter( &waiter->wait, status );
|
||||||
release_object( pipe );
|
list_remove( &waiter->entry );
|
||||||
*x = cw->next;
|
free( waiter );
|
||||||
free( cw );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void queue_connect_waiter( struct named_pipe *pipe,
|
static void named_pipe_destroy( struct object *obj)
|
||||||
void *func, void *overlapped )
|
{
|
||||||
|
struct named_pipe *pipe = (struct named_pipe *) obj;
|
||||||
|
|
||||||
|
assert( list_empty( &pipe->servers ) );
|
||||||
|
assert( !pipe->instances );
|
||||||
|
notify_connect_waiters( pipe, STATUS_HANDLES_CLOSED );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queue_connect_waiter( struct named_pipe *pipe, void *func, void *overlapped )
|
||||||
{
|
{
|
||||||
struct connect_wait *waiter;
|
struct connect_wait *waiter;
|
||||||
|
|
||||||
|
@ -255,9 +253,7 @@ static void queue_connect_waiter( struct named_pipe *pipe,
|
||||||
if( waiter )
|
if( waiter )
|
||||||
{
|
{
|
||||||
set_waiter( &waiter->wait, func, overlapped );
|
set_waiter( &waiter->wait, func, overlapped );
|
||||||
waiter->next = pipe->connect_waiters;
|
list_add_tail( &pipe->waiters, &waiter->entry );
|
||||||
pipe->connect_waiters = waiter;
|
|
||||||
grab_object( pipe );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,9 +286,6 @@ static struct fd *pipe_server_get_fd( struct object *obj )
|
||||||
case ps_wait_connect:
|
case ps_wait_connect:
|
||||||
set_error( STATUS_PIPE_DISCONNECTED );
|
set_error( STATUS_PIPE_DISCONNECTED );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
assert( 0 );
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -349,10 +342,7 @@ static void pipe_server_destroy( struct object *obj)
|
||||||
assert( server->pipe->instances );
|
assert( server->pipe->instances );
|
||||||
server->pipe->instances--;
|
server->pipe->instances--;
|
||||||
|
|
||||||
/* remove server from pipe's server list */
|
list_remove( &server->entry );
|
||||||
if( server->next ) server->next->prev = server->prev;
|
|
||||||
if( server->prev ) server->prev->next = server->next;
|
|
||||||
else server->pipe->servers = server->next;
|
|
||||||
release_object( server->pipe );
|
release_object( server->pipe );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +371,10 @@ static void pipe_client_destroy( struct object *obj)
|
||||||
case ps_disconnected_server:
|
case ps_disconnected_server:
|
||||||
server->state = ps_wait_connect;
|
server->state = ps_wait_connect;
|
||||||
break;
|
break;
|
||||||
default:
|
case ps_idle_server:
|
||||||
|
case ps_wait_open:
|
||||||
|
case ps_wait_disconnect:
|
||||||
|
case ps_wait_connect:
|
||||||
assert( 0 );
|
assert( 0 );
|
||||||
}
|
}
|
||||||
assert( server->client );
|
assert( server->client );
|
||||||
|
@ -493,9 +486,9 @@ static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
|
||||||
if( get_error() != STATUS_OBJECT_NAME_COLLISION )
|
if( get_error() != STATUS_OBJECT_NAME_COLLISION )
|
||||||
{
|
{
|
||||||
/* initialize it if it didn't already exist */
|
/* initialize it if it didn't already exist */
|
||||||
pipe->servers = 0;
|
|
||||||
pipe->instances = 0;
|
pipe->instances = 0;
|
||||||
pipe->connect_waiters = NULL;
|
list_init( &pipe->servers );
|
||||||
|
list_init( &pipe->waiters );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pipe;
|
return pipe;
|
||||||
|
@ -534,16 +527,12 @@ static struct pipe_server *create_pipe_server( struct named_pipe *pipe )
|
||||||
|
|
||||||
server->fd = NULL;
|
server->fd = NULL;
|
||||||
server->pipe = pipe;
|
server->pipe = pipe;
|
||||||
server->state = ps_none;
|
server->state = ps_idle_server;
|
||||||
server->client = NULL;
|
server->client = NULL;
|
||||||
server->flush_poll = NULL;
|
server->flush_poll = NULL;
|
||||||
server->wait.thread = NULL;
|
server->wait.thread = NULL;
|
||||||
|
|
||||||
/* add to list of pipe servers */
|
list_add_head( &pipe->servers, &server->entry );
|
||||||
if ((server->next = pipe->servers)) server->next->prev = server;
|
|
||||||
server->prev = NULL;
|
|
||||||
pipe->servers = server;
|
|
||||||
|
|
||||||
grab_object( pipe );
|
grab_object( pipe );
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
|
@ -564,19 +553,28 @@ static struct pipe_client *create_pipe_client( struct pipe_server *server )
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pipe_server *find_server( struct named_pipe *pipe,
|
static inline struct pipe_server *find_server( struct named_pipe *pipe, enum pipe_state state )
|
||||||
enum pipe_state state )
|
|
||||||
{
|
{
|
||||||
struct pipe_server *x;
|
struct pipe_server *server;
|
||||||
|
|
||||||
for( x = pipe->servers; x; x = x->next )
|
LIST_FOR_EACH_ENTRY( server, &pipe->servers, struct pipe_server, entry )
|
||||||
if( x->state == state )
|
{
|
||||||
break;
|
if (server->state == state) return (struct pipe_server *)grab_object( server );
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if( !x )
|
static inline struct pipe_server *find_server2( struct named_pipe *pipe,
|
||||||
return NULL;
|
enum pipe_state state1, enum pipe_state state2 )
|
||||||
|
{
|
||||||
|
struct pipe_server *server;
|
||||||
|
|
||||||
return (struct pipe_server *) grab_object( x );
|
LIST_FOR_EACH_ENTRY( server, &pipe->servers, struct pipe_server, entry )
|
||||||
|
{
|
||||||
|
if (server->state == state1 || server->state == state2)
|
||||||
|
return (struct pipe_server *)grab_object( server );
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DECL_HANDLER(create_named_pipe)
|
DECL_HANDLER(create_named_pipe)
|
||||||
|
@ -619,7 +617,6 @@ DECL_HANDLER(create_named_pipe)
|
||||||
server = create_pipe_server( pipe );
|
server = create_pipe_server( pipe );
|
||||||
if(server)
|
if(server)
|
||||||
{
|
{
|
||||||
server->state = ps_idle_server;
|
|
||||||
reply->handle = alloc_handle( current->process, server,
|
reply->handle = alloc_handle( current->process, server,
|
||||||
GENERIC_READ|GENERIC_WRITE, req->inherit );
|
GENERIC_READ|GENERIC_WRITE, req->inherit );
|
||||||
server->pipe->instances++;
|
server->pipe->instances++;
|
||||||
|
@ -636,8 +633,6 @@ DECL_HANDLER(open_named_pipe)
|
||||||
struct named_pipe *pipe;
|
struct named_pipe *pipe;
|
||||||
int fds[2];
|
int fds[2];
|
||||||
|
|
||||||
reply->handle = 0;
|
|
||||||
|
|
||||||
pipe = open_named_pipe( get_req_data(), get_req_data_size() );
|
pipe = open_named_pipe( get_req_data(), get_req_data_size() );
|
||||||
if ( !pipe )
|
if ( !pipe )
|
||||||
{
|
{
|
||||||
|
@ -645,10 +640,7 @@ DECL_HANDLER(open_named_pipe)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( server = pipe->servers; server; server = server->next )
|
server = find_server2( pipe, ps_idle_server, ps_wait_open );
|
||||||
if( ( server->state==ps_idle_server ) ||
|
|
||||||
( server->state==ps_wait_open ) )
|
|
||||||
break;
|
|
||||||
release_object( pipe );
|
release_object( pipe );
|
||||||
|
|
||||||
if ( !server )
|
if ( !server )
|
||||||
|
@ -685,6 +677,7 @@ DECL_HANDLER(open_named_pipe)
|
||||||
|
|
||||||
release_object( client );
|
release_object( client );
|
||||||
}
|
}
|
||||||
|
release_object( server );
|
||||||
}
|
}
|
||||||
|
|
||||||
DECL_HANDLER(connect_named_pipe)
|
DECL_HANDLER(connect_named_pipe)
|
||||||
|
@ -702,7 +695,7 @@ DECL_HANDLER(connect_named_pipe)
|
||||||
assert( !server->fd );
|
assert( !server->fd );
|
||||||
server->state = ps_wait_open;
|
server->state = ps_wait_open;
|
||||||
set_waiter( &server->wait, req->func, req->overlapped );
|
set_waiter( &server->wait, req->func, req->overlapped );
|
||||||
notify_connect_waiters( server->pipe );
|
notify_connect_waiters( server->pipe, STATUS_SUCCESS );
|
||||||
break;
|
break;
|
||||||
case ps_connected_server:
|
case ps_connected_server:
|
||||||
assert( server->fd );
|
assert( server->fd );
|
||||||
|
@ -714,7 +707,7 @@ DECL_HANDLER(connect_named_pipe)
|
||||||
case ps_wait_disconnect:
|
case ps_wait_disconnect:
|
||||||
set_error( STATUS_NO_DATA_DETECTED );
|
set_error( STATUS_NO_DATA_DETECTED );
|
||||||
break;
|
break;
|
||||||
default:
|
case ps_wait_open:
|
||||||
set_error( STATUS_INVALID_HANDLE );
|
set_error( STATUS_INVALID_HANDLE );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -780,8 +773,12 @@ DECL_HANDLER(disconnect_named_pipe)
|
||||||
reply->fd = flush_cached_fd( current->process, req->handle );
|
reply->fd = flush_cached_fd( current->process, req->handle );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case ps_idle_server:
|
||||||
|
case ps_wait_open:
|
||||||
|
case ps_disconnected_server:
|
||||||
|
case ps_wait_connect:
|
||||||
set_error( STATUS_PIPE_DISCONNECTED );
|
set_error( STATUS_PIPE_DISCONNECTED );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
release_object( server );
|
release_object( server );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue