Commit 1dca5e24 authored by Alexandre Julliard's avatar Alexandre Julliard

Moved poll handling to the generic part of the server objects.

Fixed busy waiting on POLLERR events. Merged struct client into struct thread.
parent 81ee21dd
......@@ -25,7 +25,6 @@ C_SRCS = \
semaphore.c \
snapshot.c \
sock.c \
socket.c \
thread.c \
timer.c \
trace.c \
......
......@@ -27,24 +27,26 @@ static int change_signaled( struct object *obj, struct thread *thread );
static const struct object_ops change_ops =
{
sizeof(struct change),
change_dump,
add_queue,
remove_queue,
change_signaled,
no_satisfied,
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
no_destroy
sizeof(struct change), /* size */
change_dump, /* dump */
add_queue, /* add_queue */
remove_queue, /* remove_queue */
change_signaled, /* signaled */
no_satisfied, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
no_destroy /* destroy */
};
static struct change *create_change_notification( int subtree, int filter )
{
struct change *change;
if ((change = alloc_object( &change_ops )))
if ((change = alloc_object( &change_ops, -1 )))
{
change->subtree = subtree;
change->filter = filter;
......
......@@ -34,23 +34,25 @@ static int device_get_info( struct object *obj, struct get_file_info_request *re
static const struct object_ops device_ops =
{
sizeof(struct device),
device_dump,
no_add_queue,
NULL, /* should never get called */
NULL, /* should never get called */
NULL, /* should never get called */
no_read_fd,
no_write_fd,
no_flush,
device_get_info,
no_destroy
sizeof(struct device), /* size */
device_dump, /* dump */
no_add_queue, /* add_queue */
NULL, /* remove_queue */
NULL, /* signaled */
NULL, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
device_get_info, /* get_file_info */
no_destroy /* destroy */
};
static struct device *create_device( int id )
{
struct device *dev;
if ((dev = alloc_object( &device_ops )))
if ((dev = alloc_object( &device_ops, -1 )))
{
dev->id = id;
}
......
......@@ -28,17 +28,19 @@ static int event_satisfied( struct object *obj, struct thread *thread );
static const struct object_ops event_ops =
{
sizeof(struct event),
event_dump,
add_queue,
remove_queue,
event_signaled,
event_satisfied,
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
no_destroy
sizeof(struct event), /* size */
event_dump, /* dump */
add_queue, /* add_queue */
remove_queue, /* remove_queue */
event_signaled, /* signaled */
event_satisfied, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
no_destroy /* destroy */
};
......
......@@ -32,8 +32,6 @@
struct file
{
struct object obj; /* object header */
int fd; /* file descriptor */
int select; /* select user id */
struct file *next; /* next file in hashing list */
char *name; /* file name */
unsigned int access; /* file access (GENERIC_READ/WRITE) */
......@@ -46,9 +44,7 @@ struct file
static struct file *file_hash[NAME_HASH_SIZE];
static void file_dump( struct object *obj, int verbose );
static int file_add_queue( struct object *obj, struct wait_queue_entry *entry );
static void file_remove_queue( struct object *obj, struct wait_queue_entry *entry );
static int file_signaled( struct object *obj, struct thread *thread );
static int file_get_poll_events( struct object *obj );
static int file_get_read_fd( struct object *obj );
static int file_get_write_fd( struct object *obj );
static int file_flush( struct object *obj );
......@@ -57,17 +53,19 @@ static void file_destroy( struct object *obj );
static const struct object_ops file_ops =
{
sizeof(struct file),
file_dump,
file_add_queue,
file_remove_queue,
file_signaled,
no_satisfied,
file_get_read_fd,
file_get_write_fd,
file_flush,
file_get_info,
file_destroy
sizeof(struct file), /* size */
file_dump, /* dump */
default_poll_add_queue, /* add_queue */
default_poll_remove_queue, /* remove_queue */
default_poll_signaled, /* signaled */
no_satisfied, /* satisfied */
file_get_poll_events, /* get_poll_events */
default_poll_event, /* poll_event */
file_get_read_fd, /* get_read_fd */
file_get_write_fd, /* get_write_fd */
file_flush, /* flush */
file_get_info, /* get_file_info */
file_destroy /* destroy */
};
......@@ -103,23 +101,19 @@ static int check_sharing( const char *name, int hash, unsigned int access,
return 0;
}
/* create a file from a file descriptor */
/* if the function fails the fd is closed */
static struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing,
unsigned int attrs )
{
struct file *file;
if ((file = alloc_object( &file_ops )))
if ((file = alloc_object( &file_ops, fd )))
{
file->name = NULL;
file->next = NULL;
file->fd = fd;
file->access = access;
file->flags = attrs;
file->sharing = sharing;
if ((file->select = add_select_user( fd, default_select_event, file )) == -1)
{
release_object( file );
file = NULL;
}
}
return file;
}
......@@ -171,7 +165,11 @@ static struct file *create_file( const char *nameptr, size_t len, unsigned int a
goto error;
}
if (!(file = create_file_for_fd( fd, access, sharing, attrs ))) goto error;
if (!(file = create_file_for_fd( fd, access, sharing, attrs )))
{
free( name );
return NULL;
}
file->name = name;
file->next = file_hash[hash];
file_hash[hash] = file;
......@@ -212,81 +210,41 @@ int create_anonymous_file(void)
/* Create a temp file for anonymous mappings */
struct file *create_temp_file( int access )
{
struct file *file;
int fd;
if ((fd = create_anonymous_file()) == -1) return NULL;
if (!(file = create_file_for_fd( fd, access, 0, 0 ))) close( fd );
return file;
return create_file_for_fd( fd, access, 0, 0 );
}
static void file_dump( struct object *obj, int verbose )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
fprintf( stderr, "File fd=%d flags=%08x name='%s'\n", file->fd, file->flags, file->name );
fprintf( stderr, "File fd=%d flags=%08x name='%s'\n", file->obj.fd, file->flags, file->name );
}
static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
static int file_get_poll_events( struct object *obj )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
if (!obj->head) /* first on the queue */
{
int events = 0;
if (file->access & GENERIC_READ) events |= POLLIN;
if (file->access & GENERIC_WRITE) events |= POLLOUT;
set_select_events( file->select, events );
}
add_queue( obj, entry );
return 1;
}
static void file_remove_queue( struct object *obj, struct wait_queue_entry *entry )
{
struct file *file = (struct file *)grab_object(obj);
assert( obj->ops == &file_ops );
remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */
set_select_events( file->select, 0 );
release_object( obj );
}
static int file_signaled( struct object *obj, struct thread *thread )
{
int events = 0;
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
if (file->access & GENERIC_READ) events |= POLLIN;
if (file->access & GENERIC_WRITE) events |= POLLOUT;
if (check_select_events( file->fd, events ))
{
/* stop waiting on select() if we are signaled */
set_select_events( file->select, 0 );
return 1;
}
else
{
/* restart waiting on select() if we are no longer signaled */
if (obj->head) set_select_events( file->select, events );
return 0;
}
return events;
}
static int file_get_read_fd( struct object *obj )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
return dup( file->fd );
return dup( file->obj.fd );
}
static int file_get_write_fd( struct object *obj )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
return dup( file->fd );
return dup( file->obj.fd );
}
static int file_flush( struct object *obj )
......@@ -295,7 +253,7 @@ static int file_flush( struct object *obj )
struct file *file = (struct file *)grab_object(obj);
assert( obj->ops == &file_ops );
ret = (fsync( file->fd ) != -1);
ret = (fsync( file->obj.fd ) != -1);
if (!ret) file_set_error();
release_object( file );
return ret;
......@@ -307,13 +265,13 @@ static int file_get_info( struct object *obj, struct get_file_info_request *req
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
if (fstat( file->fd, &st ) == -1)
if (fstat( file->obj.fd, &st ) == -1)
{
file_set_error();
return 0;
}
if (S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) ||
S_ISSOCK(st.st_mode) || isatty(file->fd)) req->type = FILE_TYPE_CHAR;
S_ISSOCK(st.st_mode) || isatty(file->obj.fd)) req->type = FILE_TYPE_CHAR;
else req->type = FILE_TYPE_DISK;
if (S_ISDIR(st.st_mode)) req->attr = FILE_ATTRIBUTE_DIRECTORY;
else req->attr = FILE_ATTRIBUTE_ARCHIVE;
......@@ -344,7 +302,6 @@ static void file_destroy( struct object *obj )
if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name );
free( file->name );
}
remove_select_user( file->select );
}
/* set the last error depending on errno */
......@@ -379,7 +336,7 @@ struct file *get_file_obj( struct process *process, int handle, unsigned int acc
int file_get_mmap_fd( struct file *file )
{
return dup( file->fd );
return dup( file->obj.fd );
}
static int set_file_pointer( int handle, int *low, int *high, int whence )
......@@ -396,7 +353,7 @@ static int set_file_pointer( int handle, int *low, int *high, int whence )
if (!(file = get_file_obj( current->process, handle, 0 )))
return 0;
if ((result = lseek( file->fd, *low, whence )) == -1)
if ((result = lseek( file->obj.fd, *low, whence )) == -1)
{
/* Check for seek before start of file */
if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
......@@ -418,8 +375,8 @@ static int truncate_file( int handle )
if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE )))
return 0;
if (((result = lseek( file->fd, 0, SEEK_CUR )) == -1) ||
(ftruncate( file->fd, result ) == -1))
if (((result = lseek( file->obj.fd, 0, SEEK_CUR )) == -1) ||
(ftruncate( file->obj.fd, result ) == -1))
{
file_set_error();
release_object( file );
......@@ -440,13 +397,13 @@ int grow_file( struct file *file, int size_high, int size_low )
set_error( ERROR_INVALID_PARAMETER );
return 0;
}
if (fstat( file->fd, &st ) == -1)
if (fstat( file->obj.fd, &st ) == -1)
{
file_set_error();
return 0;
}
if (st.st_size >= size_low) return 1; /* already large enough */
if (ftruncate( file->fd, size_low ) != -1) return 1;
if (ftruncate( file->obj.fd, size_low ) != -1) return 1;
file_set_error();
return 0;
}
......@@ -518,7 +475,6 @@ DECL_HANDLER(alloc_file_handle)
req->handle = alloc_handle( current->process, file, req->access, 0 );
release_object( file );
}
else close( fd );
}
else file_set_error();
}
......
......@@ -69,17 +69,19 @@ static void handle_table_destroy( struct object *obj );
static const struct object_ops handle_table_ops =
{
sizeof(struct handle_table),
handle_table_dump,
no_add_queue,
NULL, /* should never get called */
NULL, /* should never get called */
NULL, /* should never get called */
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
handle_table_destroy
sizeof(struct handle_table), /* size */
handle_table_dump, /* dump */
no_add_queue, /* add_queue */
NULL, /* remove_queue */
NULL, /* signaled */
NULL, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
handle_table_destroy /* destroy */
};
/* dump a handle table */
......@@ -127,7 +129,7 @@ struct object *alloc_handle_table( struct process *process, int count )
struct handle_table *table;
if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
if (!(table = alloc_object( &handle_table_ops )))
if (!(table = alloc_object( &handle_table_ops, -1 )))
return NULL;
table->process = process;
table->count = count;
......
......@@ -32,17 +32,19 @@ static void mapping_destroy( struct object *obj );
static const struct object_ops mapping_ops =
{
sizeof(struct mapping),
mapping_dump,
no_add_queue,
NULL, /* should never get called */
NULL, /* should never get called */
NULL, /* should never get called */
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
mapping_destroy
sizeof(struct mapping), /* size */
mapping_dump, /* dump */
no_add_queue, /* add_queue */
NULL, /* remove_queue */
NULL, /* signaled */
NULL, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
mapping_destroy /* destroy */
};
#ifdef __i386__
......
......@@ -32,17 +32,19 @@ static void mutex_destroy( struct object *obj );
static const struct object_ops mutex_ops =
{
sizeof(struct mutex),
mutex_dump,
add_queue,
remove_queue,
mutex_signaled,
mutex_satisfied,
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
mutex_destroy
sizeof(struct mutex), /* size */
mutex_dump, /* dump */
add_queue, /* add_queue */
remove_queue, /* remove_queue */
mutex_signaled, /* signaled */
mutex_satisfied, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
mutex_destroy /* destroy */
};
......
......@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "winerror.h"
#include "thread.h"
......@@ -121,23 +122,34 @@ static void set_object_name( struct object *obj, struct object_name *ptr )
}
/* allocate and initialize an object */
void *alloc_object( const struct object_ops *ops )
/* if the function fails the fd is closed */
void *alloc_object( const struct object_ops *ops, int fd )
{
struct object *obj = mem_alloc( ops->size );
if (obj)
{
obj->refcount = 1;
obj->fd = fd;
obj->select = -1;
obj->ops = ops;
obj->head = NULL;
obj->tail = NULL;
obj->name = NULL;
if ((fd != -1) && (add_select_user( obj ) == -1))
{
close( fd );
free( obj );
return NULL;
}
#ifdef DEBUG_OBJECTS
obj->prev = NULL;
if ((obj->next = first) != NULL) obj->next->prev = obj;
first = obj;
#endif
return obj;
}
return obj;
if (fd != -1) close( fd );
return NULL;
}
void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len )
......@@ -145,7 +157,7 @@ void *create_named_object( const struct object_ops *ops, const WCHAR *name, size
struct object *obj;
struct object_name *name_ptr;
if (!name || !len) return alloc_object( ops );
if (!name || !len) return alloc_object( ops, -1 );
if (!(name_ptr = alloc_name( name, len ))) return NULL;
if ((obj = find_object( name_ptr->name, name_ptr->len )))
......@@ -159,7 +171,7 @@ void *create_named_object( const struct object_ops *ops, const WCHAR *name, size
set_error( ERROR_INVALID_HANDLE );
return NULL;
}
if ((obj = alloc_object( ops )))
if ((obj = alloc_object( ops, -1 )))
{
set_object_name( obj, name_ptr );
clear_error();
......@@ -199,14 +211,16 @@ void release_object( void *ptr )
/* if the refcount is 0, nobody can be in the wait queue */
assert( !obj->head );
assert( !obj->tail );
obj->ops->destroy( obj );
if (obj->name) free_name( obj );
if (obj->select != -1) remove_select_user( obj );
if (obj->fd != -1) close( obj->fd );
#ifdef DEBUG_OBJECTS
if (obj->next) obj->next->prev = obj->prev;
if (obj->prev) obj->prev->next = obj->next;
else first = obj->next;
#endif
obj->ops->destroy( obj );
memset( obj, 0xaa, obj->ops->size );
#endif
free( obj );
}
}
......@@ -224,7 +238,7 @@ struct object *find_object( const WCHAR *name, size_t len )
return NULL;
}
/* functions for unimplemented object operations */
/* functions for unimplemented/default object operations */
int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
{
......@@ -265,9 +279,45 @@ void no_destroy( struct object *obj )
{
}
void default_select_event( int event, void *private )
/* default add_queue() routine for objects that poll() on an fd */
int default_poll_add_queue( struct object *obj, struct wait_queue_entry *entry )
{
if (!obj->head) /* first on the queue */
set_select_events( obj, obj->ops->get_poll_events( obj ) );
add_queue( obj, entry );
return 1;
}
/* default remove_queue() routine for objects that poll() on an fd */
void default_poll_remove_queue( struct object *obj, struct wait_queue_entry *entry )
{
grab_object(obj);
remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */
set_select_events( obj, 0 );
release_object( obj );
}
/* default signaled() routine for objects that poll() on an fd */
int default_poll_signaled( struct object *obj, struct thread *thread )
{
int events = obj->ops->get_poll_events( obj );
if (check_select_events( obj->fd, events ))
{
/* stop waiting on select() if we are signaled */
set_select_events( obj, 0 );
return 1;
}
/* restart waiting on select() if we are no longer signaled */
if (obj->head) set_select_events( obj, events );
return 0;
}
/* default handler for poll() events */
void default_poll_event( struct object *obj, int event )
{
struct object *obj = (struct object *)private;
assert( obj );
/* an error occurred, stop polling this fd to avoid busy-looping */
if (event & (POLLERR | POLLHUP)) set_select_events( obj, -1 );
wake_up( obj, 0 );
}
......@@ -41,6 +41,10 @@ struct object_ops
int (*signaled)(struct object *,struct thread *);
/* wait satisfied; return 1 if abandoned */
int (*satisfied)(struct object *,struct thread *);
/* get the events we want to poll() for on this object */
int (*get_poll_events)(struct object *);
/* a poll() event occured */
void (*poll_event)(struct object *,int event);
/* return a Unix fd that can be used to read from the object */
int (*get_read_fd)(struct object *);
/* return a Unix fd that can be used to write to the object */
......@@ -55,7 +59,9 @@ struct object_ops
struct object
{
unsigned int refcount;
unsigned int refcount; /* reference count */
int fd; /* file descriptor */
int select; /* select() user id */
const struct object_ops *ops;
struct wait_queue_entry *head;
struct wait_queue_entry *tail;
......@@ -68,7 +74,7 @@ struct object
extern void *mem_alloc( size_t size ); /* malloc wrapper */
extern void *memdup( const void *data, size_t len );
extern void *alloc_object( const struct object_ops *ops );
extern void *alloc_object( const struct object_ops *ops, int fd );
extern void dump_object_name( struct object *obj );
extern void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len );
/* grab/release_object can take any pointer, but you better make sure */
......@@ -83,17 +89,20 @@ extern int no_write_fd( struct object *obj );
extern int no_flush( struct object *obj );
extern int no_get_file_info( struct object *obj, struct get_file_info_request *info );
extern void no_destroy( struct object *obj );
extern void default_select_event( int event, void *private );
extern int default_poll_add_queue( struct object *obj, struct wait_queue_entry *entry );
extern void default_poll_remove_queue( struct object *obj, struct wait_queue_entry *entry );
extern int default_poll_signaled( struct object *obj, struct thread *thread );
extern void default_poll_event( struct object *obj, int event );
#ifdef DEBUG_OBJECTS
extern void dump_objects(void);
#endif
/* select functions */
extern int add_select_user( int fd, void (*func)(int, void *), void *private );
extern void remove_select_user( int user );
extern void change_select_fd( int user, int fd );
extern void set_select_events( int user, int events );
extern int add_select_user( struct object *obj );
extern void remove_select_user( struct object *obj );
extern void change_select_fd( struct object *obj, int fd );
extern void set_select_events( struct object *obj, int events );
extern int check_select_events( int fd, int events );
extern void select_loop(void);
......@@ -114,15 +123,6 @@ static inline int time_before( struct timeval *t1, struct timeval *t2 )
((t1->tv_sec == t2->tv_sec) && (t1->tv_usec < t2->tv_usec)));
}
/* socket functions */
struct client;
extern struct client *add_client( int client_fd, struct thread *self );
extern void remove_client( struct client *client, int exit_code );
extern void client_pass_fd( struct client *client, int pass_fd );
extern void client_reply( struct client *client, unsigned int res );
/* event functions */
struct event;
......
......@@ -33,15 +33,11 @@ struct pipe
{
struct object obj; /* object header */
struct pipe *other; /* the pipe other end */
int fd; /* file descriptor */
int select; /* select user id */
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_poll_events( struct object *obj );
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_request *req );
......@@ -49,17 +45,19 @@ static void pipe_destroy( struct object *obj );
static const struct object_ops pipe_ops =
{
sizeof(struct pipe),
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
sizeof(struct pipe), /* size */
pipe_dump, /* dump */
default_poll_add_queue, /* add_queue */
default_poll_remove_queue, /* remove_queue */
default_poll_signaled, /* signaled */
no_satisfied, /* satisfied */
pipe_get_poll_events, /* get_poll_events */
default_poll_event, /* poll_event */
pipe_get_read_fd, /* get_read_fd */
pipe_get_write_fd, /* get_write_fd */
no_flush, /* flush */
pipe_get_info, /* get_file_info */
pipe_destroy /* destroy */
};
......@@ -67,16 +65,10 @@ static struct pipe *create_pipe_side( int fd, int side )
{
struct pipe *pipe;
if ((pipe = alloc_object( &pipe_ops )))
if ((pipe = alloc_object( &pipe_ops, fd )))
{
pipe->fd = fd;
pipe->other = NULL;
pipe->side = side;
if ((pipe->select = add_select_user( fd, default_select_event, pipe )) == -1)
{
release_object( pipe );
pipe = NULL;
}
}
return pipe;
}
......@@ -104,8 +96,7 @@ static int create_pipe( struct object *obj[2] )
}
release_object( read_pipe );
}
close( fd[0] );
close( fd[1] );
else close( fd[1] );
return 0;
}
......@@ -114,49 +105,14 @@ 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 );
(pipe->side == READ_SIDE) ? "read" : "write", pipe->obj.fd );
}
static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry )
static int pipe_get_poll_events( struct object *obj )
{
struct pipe *pipe = (struct pipe *)obj;
assert( obj->ops == &pipe_ops );
if (!obj->head) /* first on the queue */
set_select_events( pipe->select, (pipe->side == READ_SIDE) ? POLLIN : POLLOUT );
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 */
set_select_events( pipe->select, 0 );
release_object( obj );
}
static int pipe_signaled( struct object *obj, struct thread *thread )
{
int event;
struct pipe *pipe = (struct pipe *)obj;
assert( obj->ops == &pipe_ops );
event = (pipe->side == READ_SIDE) ? POLLIN : POLLOUT;
if (check_select_events( pipe->fd, event ))
{
/* stop waiting on select() if we are signaled */
set_select_events( pipe->select, 0 );
return 1;
}
else
{
/* restart waiting on select() if we are no longer signaled */
if (obj->head) set_select_events( pipe->select, event );
return 0;
}
return (pipe->side == READ_SIDE) ? POLLIN : POLLOUT;
}
static int pipe_get_read_fd( struct object *obj )
......@@ -174,7 +130,7 @@ static int pipe_get_read_fd( struct object *obj )
set_error( ERROR_ACCESS_DENIED );
return -1;
}
return dup( pipe->fd );
return dup( pipe->obj.fd );
}
static int pipe_get_write_fd( struct object *obj )
......@@ -192,7 +148,7 @@ static int pipe_get_write_fd( struct object *obj )
set_error( ERROR_ACCESS_DENIED );
return -1;
}
return dup( pipe->fd );
return dup( pipe->obj.fd );
}
static int pipe_get_info( struct object *obj, struct get_file_info_request *req )
......@@ -216,7 +172,6 @@ static void pipe_destroy( struct object *obj )
assert( obj->ops == &pipe_ops );
if (pipe->other) pipe->other->other = NULL;
remove_select_user( pipe->select );
}
/* create an anonymous pipe */
......
......@@ -36,17 +36,19 @@ static void process_destroy( struct object *obj );
static const struct object_ops process_ops =
{
sizeof(struct process),
process_dump,
add_queue,
remove_queue,
process_signaled,
no_satisfied,
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
process_destroy
sizeof(struct process), /* size */
process_dump, /* dump */
add_queue, /* add_queue */
remove_queue, /* remove_queue */
process_signaled, /* signaled */
no_satisfied, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
process_destroy /* destroy */
};
......@@ -56,7 +58,7 @@ static struct process *create_process( struct process *parent, struct new_proces
{
struct process *process;
if (!(process = alloc_object( &process_ops ))) return NULL;
if (!(process = alloc_object( &process_ops, -1 ))) return NULL;
process->next = NULL;
process->prev = NULL;
process->thread_list = NULL;
......
......@@ -106,17 +106,19 @@ static void key_destroy( struct object *obj );
static const struct object_ops key_ops =
{
sizeof(struct key),
key_dump,
no_add_queue,
NULL, /* should never get called */
NULL, /* should never get called */
NULL, /* should never get called */
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
key_destroy
sizeof(struct key), /* size */
key_dump, /* dump */
no_add_queue, /* add_queue */
NULL, /* remove_queue */
NULL, /* signaled */
NULL, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
key_destroy /* destroy */
};
......@@ -322,7 +324,7 @@ static WCHAR *req_strdupW( const WCHAR *str )
static struct key *alloc_key( const WCHAR *name, time_t modif )
{
struct key *key;
if ((key = (struct key *)alloc_object( &key_ops )))
if ((key = (struct key *)alloc_object( &key_ops, -1 )))
{
key->name = NULL;
key->class = NULL;
......
......@@ -4,13 +4,20 @@
* Copyright (C) 1998 Alexandre Julliard
*/
#include "config.h"
#include <assert.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <stdarg.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#include <sys/uio.h>
#include <unistd.h>
......@@ -22,9 +29,30 @@
#include "server.h"
#define WANT_REQUEST_HANDLERS
#include "request.h"
/* Some versions of glibc don't define this */
#ifndef SCM_RIGHTS
#define SCM_RIGHTS 1
#endif
struct thread *current = NULL; /* thread handling the current request */
/* socket communication static structures */
static struct iovec myiovec;
static struct msghdr msghdr = { NULL, 0, &myiovec, 1, };
#ifndef HAVE_MSGHDR_ACCRIGHTS
struct cmsg_fd
{
int len; /* sizeof structure */
int level; /* SOL_SOCKET */
int type; /* SCM_RIGHTS */
int fd; /* fd to pass */
};
static struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
#endif /* HAVE_MSGHDR_ACCRIGHTS */
/* complain about a protocol error and terminate the client connection */
void fatal_protocol_error( struct thread *thread, const char *err, ... )
{
......@@ -34,11 +62,11 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... )
fprintf( stderr, "Protocol error:%p: ", thread );
vfprintf( stderr, err, args );
va_end( args );
remove_client( thread->client, PROTOCOL_ERROR );
kill_thread( thread, PROTOCOL_ERROR );
}
/* call a request handler */
void call_req_handler( struct thread *thread, enum request req, int fd )
static void call_req_handler( struct thread *thread, enum request req, int fd )
{
current = thread;
clear_error();
......@@ -65,31 +93,109 @@ void call_timeout_handler( void *thread )
current = NULL;
}
/* a thread has been killed */
void call_kill_handler( struct thread *thread, int exit_code )
{
/* must be reentrant WRT call_req_handler */
struct thread *old_current = current;
current = thread;
if (current)
{
if (debug_level) trace_kill( exit_code );
thread_killed( current, exit_code );
}
current = (old_current != thread) ? old_current : NULL;
}
/* set the fd to pass to the thread */
void set_reply_fd( struct thread *thread, int pass_fd )
{
client_pass_fd( thread->client, pass_fd );
assert( thread->pass_fd == -1 );
thread->pass_fd = pass_fd;
}
/* send a reply to a thread */
void send_reply( struct thread *thread )
{
if (thread->state == SLEEPING) thread->state = RUNNING;
client_reply( thread->client, thread->error );
if (debug_level) trace_reply( thread );
if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT );
}
/* read a message from a client that has something to say */
void read_request( struct thread *thread )
{
int ret;
enum request req;
#ifdef HAVE_MSGHDR_ACCRIGHTS
msghdr.msg_accrightslen = sizeof(int);
msghdr.msg_accrights = (void *)&thread->pass_fd;
#else /* HAVE_MSGHDR_ACCRIGHTS */
msghdr.msg_control = &cmsg;
msghdr.msg_controllen = sizeof(cmsg);
cmsg.fd = -1;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
assert( thread->pass_fd == -1 );
myiovec.iov_base = (void *)&req;
myiovec.iov_len = sizeof(req);
ret = recvmsg( thread->obj.fd, &msghdr, 0 );
#ifndef HAVE_MSGHDR_ACCRIGHTS
thread->pass_fd = cmsg.fd;
#endif
if (ret == sizeof(req))
{
int pass_fd = thread->pass_fd;
thread->pass_fd = -1;
call_req_handler( thread, req, pass_fd );
if (pass_fd != -1) close( pass_fd );
return;
}
if (ret == -1)
{
perror("recvmsg");
kill_thread( thread, BROKEN_PIPE );
return;
}
if (!ret) /* closed pipe */
{
kill_thread( thread, BROKEN_PIPE );
return;
}
fatal_protocol_error( thread, "partial message received %d/%d\n", ret, sizeof(req) );
}
/* send a message to a client that is ready to receive something */
int write_request( struct thread *thread )
{
int ret;
if (thread->pass_fd == -1)
{
ret = write( thread->obj.fd, &thread->error, sizeof(thread->error) );
if (ret == sizeof(thread->error)) goto ok;
}
else /* we have an fd to send */
{
#ifdef HAVE_MSGHDR_ACCRIGHTS
msghdr.msg_accrightslen = sizeof(int);
msghdr.msg_accrights = (void *)&thread->pass_fd;
#else /* HAVE_MSGHDR_ACCRIGHTS */
msghdr.msg_control = &cmsg;
msghdr.msg_controllen = sizeof(cmsg);
cmsg.fd = thread->pass_fd;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
myiovec.iov_base = (void *)&thread->error;
myiovec.iov_len = sizeof(thread->error);
ret = sendmsg( thread->obj.fd, &msghdr, 0 );
close( thread->pass_fd );
thread->pass_fd = -1;
if (ret == sizeof(thread->error)) goto ok;
}
if (ret == -1)
{
if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
if (errno != EPIPE) perror("sendmsg");
}
else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(thread->error) );
kill_thread( thread, BROKEN_PIPE );
return -1;
ok:
set_select_events( &thread->obj, POLLIN );
return 1;
}
/* set the debug level */
......
......@@ -26,17 +26,17 @@
/* request functions */
extern void read_request( struct thread *thread );
extern int write_request( struct thread *thread );
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
extern void call_req_handler( struct thread *thread, enum request req, int fd );
extern void call_timeout_handler( void *thread );
extern void call_kill_handler( struct thread *thread, int exit_code );
extern void set_reply_fd( struct thread *thread, int pass_fd );
extern void send_reply( struct thread *thread );
extern void trace_request( enum request req, int fd );
extern void trace_timeout(void);
extern void trace_kill( int exit_code );
extern void trace_reply( struct thread *thread, unsigned int res, int pass_fd );
extern void trace_kill( struct thread *thread );
extern void trace_reply( struct thread *thread );
/* get the request buffer */
static inline void *get_req_ptr( struct thread *thread )
......
......@@ -19,12 +19,6 @@
#include "thread.h"
struct poll_user
{
void (*func)(int event, void *private); /* callback function */
void *private; /* callback private data */
};
struct timeout_user
{
struct timeout_user *next; /* next in sorted timeout list */
......@@ -34,32 +28,31 @@ struct timeout_user
void *private; /* callback private data */
};
static struct poll_user *poll_users; /* users array */
static struct object **poll_users; /* users array */
static struct pollfd *pollfd; /* poll fd array */
static int nb_users; /* count of array entries actually in use */
static int active_users; /* current number of active users */
static int allocated_users; /* count of allocated entries in the array */
static struct poll_user *freelist; /* list of free entries in the array */
static struct object **freelist; /* list of free entries in the array */
static struct timeout_user *timeout_head; /* sorted timeouts list head */
static struct timeout_user *timeout_tail; /* sorted timeouts list tail */
/* add a user and return an opaque handle to it, or -1 on failure */
int add_select_user( int fd, void (*func)(int, void *), void *private )
int add_select_user( struct object *obj )
{
int ret;
if (freelist)
{
ret = freelist - poll_users;
freelist = poll_users[ret].private;
assert( !poll_users[ret].func );
freelist = (struct object **)poll_users[ret];
}
else
{
if (nb_users == allocated_users)
{
struct poll_user *newusers;
struct object **newusers;
struct pollfd *newpoll;
int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
......@@ -74,43 +67,53 @@ int add_select_user( int fd, void (*func)(int, void *), void *private )
}
ret = nb_users++;
}
pollfd[ret].fd = fd;
pollfd[ret].fd = obj->fd;
pollfd[ret].events = 0;
pollfd[ret].revents = 0;
poll_users[ret].func = func;
poll_users[ret].private = private;
poll_users[ret] = obj;
obj->select = ret;
active_users++;
return ret;
}
/* remove a user and close its fd */
void remove_select_user( int user )
/* remove an object from the select list and close its fd */
void remove_select_user( struct object *obj )
{
if (user == -1) return; /* avoids checking in all callers */
assert( poll_users[user].func );
close( pollfd[user].fd );
int user = obj->select;
assert( poll_users[user] == obj );
pollfd[user].fd = -1;
pollfd[user].events = 0;
pollfd[user].revents = 0;
poll_users[user].func = NULL;
poll_users[user].private = freelist;
poll_users[user] = (struct object *)freelist;
freelist = &poll_users[user];
close( obj->fd );
obj->fd = -1;
obj->select = -1;
active_users--;
}
/* change the fd of a select user (the old fd is closed) */
void change_select_fd( int user, int fd )
/* change the fd of an object (the old fd is closed) */
void change_select_fd( struct object *obj, int fd )
{
assert( poll_users[user].func );
close( pollfd[user].fd );
int user = obj->select;
assert( poll_users[user] == obj );
pollfd[user].fd = fd;
close( obj->fd );
obj->fd = fd;
}
/* set the events that select waits for on this fd */
void set_select_events( int user, int events )
void set_select_events( struct object *obj, int events )
{
assert( poll_users[user].func );
pollfd[user].events = events;
int user = obj->select;
assert( poll_users[user] == obj );
if (events == -1) /* stop waiting on this fd completely */
{
pollfd[user].fd = -1;
pollfd[user].events = 0;
pollfd[user].revents = 0;
}
else if (pollfd[user].fd != -1) pollfd[user].events = events;
}
/* check if events are pending */
......@@ -259,7 +262,7 @@ void select_loop(void)
{
if (pollfd[i].revents)
{
poll_users[i].func( pollfd[i].revents, poll_users[i].private );
poll_users[i]->ops->poll_event( poll_users[i], pollfd[i].revents );
if (!--ret) break;
}
}
......
......@@ -28,17 +28,19 @@ static int semaphore_satisfied( struct object *obj, struct thread *thread );
static const struct object_ops semaphore_ops =
{
sizeof(struct semaphore),
semaphore_dump,
add_queue,
remove_queue,
semaphore_signaled,
semaphore_satisfied,
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
no_destroy
sizeof(struct semaphore), /* size */
semaphore_dump, /* dump */
add_queue, /* add_queue */
remove_queue, /* remove_queue */
semaphore_signaled, /* signaled */
semaphore_satisfied, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
no_destroy /* destroy */
};
......
......@@ -33,17 +33,19 @@ static void snapshot_destroy( struct object *obj );
static const struct object_ops snapshot_ops =
{
sizeof(struct snapshot),
snapshot_dump,
no_add_queue,
NULL, /* should never get called */
NULL, /* should never get called */
NULL, /* should never get called */
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
snapshot_destroy
sizeof(struct snapshot), /* size */
snapshot_dump, /* dump */
no_add_queue, /* add_queue */
NULL, /* remove_queue */
NULL, /* signaled */
NULL, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
snapshot_destroy /* destroy */
};
......@@ -52,7 +54,7 @@ static struct snapshot *create_snapshot( int flags )
{
struct snapshot *snapshot;
if ((snapshot = alloc_object( &snapshot_ops )))
if ((snapshot = alloc_object( &snapshot_ops, -1 )))
{
if (flags & TH32CS_SNAPPROCESS)
snapshot->process = process_snap( &snapshot->process_count );
......
/*
* Server-side socket communication functions
*
* Copyright (C) 1998 Alexandre Julliard
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#include <sys/uio.h>
#include <unistd.h>
#include "object.h"
#include "request.h"
/* Some versions of glibc don't define this */
#ifndef SCM_RIGHTS
#define SCM_RIGHTS 1
#endif
/* client structure */
struct client
{
int fd; /* socket file descriptor */
int select; /* select user id */
unsigned int res; /* current result to send */
int pass_fd; /* fd to pass to and from the client */
struct thread *self; /* client thread (opaque pointer) */
struct timeout_user *timeout; /* current timeout (opaque pointer) */
};
/* socket communication static structures */
static struct iovec myiovec;
static struct msghdr msghdr = { NULL, 0, &myiovec, 1, };
#ifndef HAVE_MSGHDR_ACCRIGHTS
struct cmsg_fd
{
int len; /* sizeof structure */
int level; /* SOL_SOCKET */
int type; /* SCM_RIGHTS */
int fd; /* fd to pass */
};
static struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
#endif /* HAVE_MSGHDR_ACCRIGHTS */
/* send a message to a client that is ready to receive something */
static int do_write( struct client *client )
{
int ret;
if (client->pass_fd == -1)
{
ret = write( client->fd, &client->res, sizeof(client->res) );
if (ret == sizeof(client->res)) goto ok;
}
else /* we have an fd to send */
{
#ifdef HAVE_MSGHDR_ACCRIGHTS
msghdr.msg_accrightslen = sizeof(int);
msghdr.msg_accrights = (void *)&client->pass_fd;
#else /* HAVE_MSGHDR_ACCRIGHTS */
msghdr.msg_control = &cmsg;
msghdr.msg_controllen = sizeof(cmsg);
cmsg.fd = client->pass_fd;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
myiovec.iov_base = (void *)&client->res;
myiovec.iov_len = sizeof(client->res);
ret = sendmsg( client->fd, &msghdr, 0 );
close( client->pass_fd );
client->pass_fd = -1;
if (ret == sizeof(client->res)) goto ok;
}
if (ret == -1)
{
if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
if (errno != EPIPE) perror("sendmsg");
}
else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(client->res) );
remove_client( client, BROKEN_PIPE );
return -1;
ok:
set_select_events( client->select, POLLIN );
return 1;
}
/* read a message from a client that has something to say */
static void do_read( struct client *client )
{
int ret;
enum request req;
#ifdef HAVE_MSGHDR_ACCRIGHTS
msghdr.msg_accrightslen = sizeof(int);
msghdr.msg_accrights = (void *)&client->pass_fd;
#else /* HAVE_MSGHDR_ACCRIGHTS */
msghdr.msg_control = &cmsg;
msghdr.msg_controllen = sizeof(cmsg);
cmsg.fd = -1;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
assert( client->pass_fd == -1 );
myiovec.iov_base = (void *)&req;
myiovec.iov_len = sizeof(req);
ret = recvmsg( client->fd, &msghdr, 0 );
#ifndef HAVE_MSGHDR_ACCRIGHTS
client->pass_fd = cmsg.fd;
#endif
if (ret == sizeof(req))
{
int pass_fd = client->pass_fd;
client->pass_fd = -1;
call_req_handler( client->self, req, pass_fd );
if (pass_fd != -1) close( pass_fd );
return;
}
if (ret == -1)
{
perror("recvmsg");
remove_client( client, BROKEN_PIPE );
return;
}
if (!ret) /* closed pipe */
{
remove_client( client, BROKEN_PIPE );
return;
}
fatal_protocol_error( client->self, "partial message received %d/%d\n", ret, sizeof(req) );
}
/* handle a client event */
static void client_event( int event, void *private )
{
struct client *client = (struct client *)private;
if (event & (POLLERR | POLLHUP)) remove_client( client, BROKEN_PIPE );
else
{
if (event & POLLOUT) do_write( client );
if (event & POLLIN) do_read( client );
}
}
/*******************************************************************/
/* server-side exported functions */
/* add a client */
struct client *add_client( int fd, struct thread *self )
{
int flags;
struct client *client = mem_alloc( sizeof(*client) );
if (!client) return NULL;
flags = fcntl( fd, F_GETFL, 0 );
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
client->fd = fd;
client->self = self;
client->timeout = NULL;
client->pass_fd = -1;
if ((client->select = add_select_user( fd, client_event, client )) == -1)
{
free( client );
return NULL;
}
set_select_events( client->select, POLLIN );
return client;
}
/* remove a client */
void remove_client( struct client *client, int exit_code )
{
assert( client );
call_kill_handler( client->self, exit_code );
if (client->timeout) remove_timeout_user( client->timeout );
remove_select_user( client->select );
/* Purge messages */
if (client->pass_fd != -1) close( client->pass_fd );
free( client );
}
/* set the fd to pass to the client */
void client_pass_fd( struct client *client, int pass_fd )
{
assert( client->pass_fd == -1 );
client->pass_fd = pass_fd;
}
/* send a reply to a client */
void client_reply( struct client *client, unsigned int res )
{
if (debug_level) trace_reply( client->self, res, client->pass_fd );
client->res = res;
if (!do_write( client )) set_select_events( client->select, POLLOUT );
}
......@@ -63,21 +63,24 @@ struct thread_apc
static void dump_thread( struct object *obj, int verbose );
static int thread_signaled( struct object *obj, struct thread *thread );
extern void thread_poll_event( struct object *obj, int event );
static void destroy_thread( struct object *obj );
static const struct object_ops thread_ops =
{
sizeof(struct thread),
dump_thread,
add_queue,
remove_queue,
thread_signaled,
no_satisfied,
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
destroy_thread
sizeof(struct thread), /* size */
dump_thread, /* dump */
add_queue, /* add_queue */
remove_queue, /* remove_queue */
thread_signaled, /* signaled */
no_satisfied, /* satisfied */
NULL, /* get_poll_events */
thread_poll_event, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
destroy_thread /* destroy */
};
static struct thread *first_thread;
......@@ -105,9 +108,11 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
struct thread *thread;
int buf_fd;
if (!(thread = alloc_object( &thread_ops ))) return NULL;
int flags = fcntl( fd, F_GETFL, 0 );
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
if (!(thread = alloc_object( &thread_ops, fd ))) return NULL;
thread->client = NULL;
thread->unix_pid = 0; /* not known yet */
thread->teb = NULL;
thread->mutex = NULL;
......@@ -118,6 +123,7 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
thread->apc = NULL;
thread->apc_count = 0;
thread->error = 0;
thread->pass_fd = -1;
thread->state = RUNNING;
thread->attached = 0;
thread->exit_code = 0x103; /* STILL_ACTIVE */
......@@ -142,11 +148,8 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
add_process_thread( process, thread );
if ((buf_fd = alloc_client_buffer( thread )) == -1) goto error;
if (!(thread->client = add_client( fd, thread )))
{
close( buf_fd );
goto error;
}
set_select_events( &thread->obj, POLLIN ); /* start listening to events */
set_reply_fd( thread, buf_fd ); /* send the fd to the client */
send_reply( thread );
return thread;
......@@ -164,6 +167,20 @@ void create_initial_thread( int fd )
select_loop();
}
/* handle a client event */
void thread_poll_event( struct object *obj, int event )
{
struct thread *thread = (struct thread *)obj;
assert( obj->ops == &thread_ops );
if (event & (POLLERR | POLLHUP)) kill_thread( thread, BROKEN_PIPE );
else
{
if (event & POLLOUT) write_request( thread );
if (event & POLLIN) read_request( thread );
}
}
/* destroy a thread when its refcount is 0 */
static void destroy_thread( struct object *obj )
{
......@@ -177,6 +194,7 @@ static void destroy_thread( struct object *obj )
else first_thread = thread->next;
if (thread->apc) free( thread->apc );
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
if (thread->pass_fd != -1) close( thread->pass_fd );
}
/* dump a thread on stdout for debugging purposes */
......@@ -499,21 +517,17 @@ static int thread_queue_apc( struct thread *thread, void *func, void *param )
void kill_thread( struct thread *thread, int exit_code )
{
if (thread->state == TERMINATED) return; /* already killed */
remove_client( thread->client, exit_code ); /* this will call thread_killed */
}
/* a thread has been killed */
void thread_killed( struct thread *thread, int exit_code )
{
thread->state = TERMINATED;
thread->exit_code = exit_code;
thread->client = NULL;
if (current == thread) current = NULL;
if (debug_level) trace_kill( thread );
if (thread->wait) end_wait( thread );
debug_exit_thread( thread, exit_code );
abandon_mutexes( thread );
remove_process_thread( thread->process, thread );
wake_up( &thread->obj, 0 );
detach_thread( thread );
remove_select_user( &thread->obj );
release_object( thread );
}
......
......@@ -46,10 +46,10 @@ struct thread
struct thread_apc *apc; /* list of async procedure calls */
int apc_count; /* number of outstanding APCs */
int error; /* current error code */
int pass_fd; /* fd to pass to the client */
enum run_state state; /* running state */
int attached; /* is thread attached with ptrace? */
int exit_code; /* thread exit code */
struct client *client; /* client for socket communications */
int unix_pid; /* Unix pid of client */
void *teb; /* TEB address (in client address space) */
int priority; /* priority level */
......@@ -74,7 +74,6 @@ extern void resume_all_threads( void );
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
extern void kill_thread( struct thread *thread, int exit_code );
extern void thread_killed( struct thread *thread, int exit_code );
extern void thread_timeout(void);
extern void wake_up( struct object *obj, int max );
......
......@@ -39,17 +39,19 @@ static void timer_destroy( struct object *obj );
static const struct object_ops timer_ops =
{
sizeof(struct timer),
timer_dump,
add_queue,
remove_queue,
timer_signaled,
timer_satisfied,
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
timer_destroy
sizeof(struct timer), /* size */
timer_dump, /* dump */
add_queue, /* add_queue */
remove_queue, /* remove_queue */
timer_signaled, /* signaled */
timer_satisfied, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
timer_destroy /* destroy */
};
......
......@@ -1341,22 +1341,22 @@ void trace_timeout(void)
fprintf( stderr, "%08x: *timeout*\n", (unsigned int)current );
}
void trace_kill( int exit_code )
void trace_kill( struct thread *thread )
{
fprintf( stderr,"%08x: *killed* exit_code=%d\n",
(unsigned int)current, exit_code );
(unsigned int)thread, thread->exit_code );
}
void trace_reply( struct thread *thread, unsigned int res, int pass_fd )
void trace_reply( struct thread *thread )
{
fprintf( stderr, "%08x: %s() = %d",
(unsigned int)thread, req_names[thread->last_req], res );
(unsigned int)thread, req_names[thread->last_req], thread->error );
if (reply_dumpers[thread->last_req])
{
fprintf( stderr, " {" );
reply_dumpers[thread->last_req]( thread->buffer );
fprintf( stderr, " }" );
}
if (pass_fd != -1) fprintf( stderr, " fd=%d\n", pass_fd );
if (thread->pass_fd != -1) fprintf( stderr, " fd=%d\n", thread->pass_fd );
else fprintf( stderr, "\n" );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment