Commit 247b8aee authored by Alexandre Julliard's avatar Alexandre Julliard

Use poll() instead of select() for the server main loop.

Fixed races with SIGCHLD handling and ptrace. Minor fixes to timeout handling.
parent 9e7b45fb
......@@ -38,7 +38,8 @@ struct screen_buffer;
struct console_input
{
struct object obj; /* object header */
struct select_user select; /* select user */
int fd; /* file descriptor */
int select; /* select user id */
int mode; /* input mode */
struct screen_buffer *output; /* associated screen buffer */
int recnum; /* number of input records */
......@@ -48,7 +49,8 @@ struct console_input
struct screen_buffer
{
struct object obj; /* object header */
struct select_user select; /* select user */
int fd; /* file descriptor */
int select; /* select user id */
int mode; /* output mode */
struct console_input *input; /* associated console input */
int cursor_size; /* size of cursor (percentage filled) */
......@@ -117,16 +119,16 @@ static struct object *create_console_input( int fd )
}
if ((console_input = alloc_object( &console_input_ops )))
{
console_input->select.fd = fd;
console_input->select.func = default_select_event;
console_input->select.private = console_input;
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
console_input->output = NULL;
console_input->recnum = 0;
console_input->records = NULL;
register_select_user( &console_input->select );
return &console_input->obj;
console_input->fd = fd;
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
console_input->output = NULL;
console_input->recnum = 0;
console_input->records = NULL;
console_input->select = add_select_user( fd, default_select_event, console_input );
if (console_input->select != -1) return &console_input->obj;
release_object( console_input );
return NULL;
}
close( fd );
return NULL;
......@@ -144,16 +146,19 @@ static struct object *create_console_output( int fd, struct object *input )
}
if ((screen_buffer = alloc_object( &screen_buffer_ops )))
{
screen_buffer->select.fd = fd;
screen_buffer->select.func = default_select_event;
screen_buffer->select.private = screen_buffer;
screen_buffer->fd = fd;
screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
screen_buffer->input = console_input;
screen_buffer->cursor_size = 100;
screen_buffer->cursor_visible = 1;
screen_buffer->pid = 0;
screen_buffer->title = strdup( "Wine console" );
register_select_user( &screen_buffer->select );
screen_buffer->select = add_select_user( fd, default_select_event, screen_buffer );
if (screen_buffer->select == -1)
{
release_object( screen_buffer );
return NULL;
}
console_input->output = screen_buffer;
return &screen_buffer->obj;
}
......@@ -218,15 +223,11 @@ static int set_console_fd( int handle, int fd_in, int fd_out, int pid )
assert( !input->obj.head );
assert( !output->obj.head );
unregister_select_user( &input->select );
unregister_select_user( &output->select );
close( input->select.fd );
close( output->select.fd );
input->select.fd = fd_in;
output->select.fd = fd_out;
output->pid = pid;
register_select_user( &input->select );
register_select_user( &output->select );
change_select_fd( input->select, fd_in );
change_select_fd( output->select, fd_out );
input->fd = fd_in;
output->fd = fd_out;
output->pid = pid;
release_object( input );
release_object( output );
return 1;
......@@ -359,7 +360,7 @@ static void console_input_dump( struct object *obj, int verbose )
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
fprintf( stderr, "Console input fd=%d\n", console->select.fd );
fprintf( stderr, "Console input fd=%d\n", console->fd );
}
static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry )
......@@ -367,7 +368,7 @@ static int console_input_add_queue( struct object *obj, struct wait_queue_entry
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
if (!obj->head) /* first on the queue */
set_select_events( &console->select, READ_EVENT );
set_select_events( console->select, POLLIN );
add_queue( obj, entry );
return 1;
}
......@@ -379,7 +380,7 @@ static void console_input_remove_queue( struct object *obj, struct wait_queue_en
remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */
set_select_events( &console->select, 0 );
set_select_events( console->select, 0 );
release_object( obj );
}
......@@ -388,16 +389,16 @@ static int console_input_signaled( struct object *obj, struct thread *thread )
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
if (check_select_events( &console->select, READ_EVENT ))
if (check_select_events( console->fd, POLLIN ))
{
/* stop waiting on select() if we are signaled */
set_select_events( &console->select, 0 );
set_select_events( console->select, 0 );
return 1;
}
else
{
/* restart waiting on select() if we are no longer signaled */
if (obj->head) set_select_events( &console->select, READ_EVENT );
if (obj->head) set_select_events( console->select, POLLIN );
return 0;
}
}
......@@ -406,7 +407,7 @@ static int console_input_get_read_fd( struct object *obj )
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
return dup( console->select.fd );
return dup( console->fd );
}
static int console_get_info( struct object *obj, struct get_file_info_request *req )
......@@ -428,8 +429,7 @@ static void console_input_destroy( struct object *obj )
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
unregister_select_user( &console->select );
close( console->select.fd );
remove_select_user( console->select );
if (console->output) console->output->input = NULL;
}
......@@ -437,7 +437,7 @@ static void screen_buffer_dump( struct object *obj, int verbose )
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
fprintf( stderr, "Console screen buffer fd=%d\n", console->select.fd );
fprintf( stderr, "Console screen buffer fd=%d\n", console->fd );
}
static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry )
......@@ -445,7 +445,7 @@ static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
if (!obj->head) /* first on the queue */
set_select_events( &console->select, WRITE_EVENT );
set_select_events( console->select, POLLOUT );
add_queue( obj, entry );
return 1;
}
......@@ -457,7 +457,7 @@ static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_en
remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */
set_select_events( &console->select, 0 );
set_select_events( console->select, 0 );
release_object( obj );
}
......@@ -466,16 +466,16 @@ static int screen_buffer_signaled( struct object *obj, struct thread *thread )
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
if (check_select_events( &console->select, WRITE_EVENT ))
if (check_select_events( console->fd, POLLOUT ))
{
/* stop waiting on select() if we are signaled */
set_select_events( &console->select, 0 );
set_select_events( console->select, 0 );
return 1;
}
else
{
/* restart waiting on select() if we are no longer signaled */
if (obj->head) set_select_events( &console->select, WRITE_EVENT );
if (obj->head) set_select_events( console->select, POLLOUT );
return 0;
}
}
......@@ -484,15 +484,14 @@ static int screen_buffer_get_write_fd( struct object *obj )
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
return dup( console->select.fd );
return dup( console->fd );
}
static void screen_buffer_destroy( struct object *obj )
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
unregister_select_user( &console->select );
close( console->select.fd );
remove_select_user( console->select );
if (console->input) console->input->output = NULL;
if (console->title) free( console->title );
}
......
......@@ -218,7 +218,8 @@ static int wait_for_debug_event( int timeout )
}
if (timeout != -1) /* start the timeout */
{
make_timeout( &when, timeout );
gettimeofday( &when, 0 );
add_timeout( &when, timeout );
if (!(debug_ctx->timeout = add_timeout_user( &when, wait_event_timeout, debug_ctx )))
return 0;
}
......
......@@ -32,7 +32,8 @@
struct file
{
struct object obj; /* object header */
struct select_user select; /* select user */
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) */
......@@ -108,15 +109,17 @@ static struct file *create_file_for_fd( int fd, unsigned int access, unsigned in
struct file *file;
if ((file = alloc_object( &file_ops )))
{
file->name = NULL;
file->next = NULL;
file->select.fd = fd;
file->select.func = default_select_event;
file->select.private = file;
file->access = access;
file->flags = attrs;
file->sharing = sharing;
register_select_user( &file->select );
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;
}
......@@ -221,8 +224,7 @@ 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->select.fd, file->flags, file->name );
fprintf( stderr, "File fd=%d flags=%08x name='%s'\n", file->fd, file->flags, file->name );
}
static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
......@@ -232,9 +234,9 @@ static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
if (!obj->head) /* first on the queue */
{
int events = 0;
if (file->access & GENERIC_READ) events |= READ_EVENT;
if (file->access & GENERIC_WRITE) events |= WRITE_EVENT;
set_select_events( &file->select, events );
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;
......@@ -247,7 +249,7 @@ static void file_remove_queue( struct object *obj, struct wait_queue_entry *entr
remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */
set_select_events( &file->select, 0 );
set_select_events( file->select, 0 );
release_object( obj );
}
......@@ -257,18 +259,18 @@ static int file_signaled( struct object *obj, struct thread *thread )
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
if (file->access & GENERIC_READ) events |= READ_EVENT;
if (file->access & GENERIC_WRITE) events |= WRITE_EVENT;
if (check_select_events( &file->select, events ))
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 );
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 );
if (obj->head) set_select_events( file->select, events );
return 0;
}
}
......@@ -277,14 +279,14 @@ static int file_get_read_fd( struct object *obj )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
return dup( file->select.fd );
return dup( file->fd );
}
static int file_get_write_fd( struct object *obj )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
return dup( file->select.fd );
return dup( file->fd );
}
static int file_flush( struct object *obj )
......@@ -293,7 +295,7 @@ static int file_flush( struct object *obj )
struct file *file = (struct file *)grab_object(obj);
assert( obj->ops == &file_ops );
ret = (fsync( file->select.fd ) != -1);
ret = (fsync( file->fd ) != -1);
if (!ret) file_set_error();
release_object( file );
return ret;
......@@ -305,13 +307,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->select.fd, &st ) == -1)
if (fstat( file->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->select.fd)) req->type = FILE_TYPE_CHAR;
S_ISSOCK(st.st_mode) || isatty(file->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;
......@@ -342,8 +344,7 @@ static void file_destroy( struct object *obj )
if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name );
free( file->name );
}
unregister_select_user( &file->select );
close( file->select.fd );
remove_select_user( file->select );
}
/* set the last error depending on errno */
......@@ -378,7 +379,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->select.fd );
return dup( file->fd );
}
static int set_file_pointer( int handle, int *low, int *high, int whence )
......@@ -395,7 +396,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->select.fd, *low, whence )) == -1)
if ((result = lseek( file->fd, *low, whence )) == -1)
{
/* Check for seek before start of file */
if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
......@@ -417,8 +418,8 @@ static int truncate_file( int handle )
if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE )))
return 0;
if (((result = lseek( file->select.fd, 0, SEEK_CUR )) == -1) ||
(ftruncate( file->select.fd, result ) == -1))
if (((result = lseek( file->fd, 0, SEEK_CUR )) == -1) ||
(ftruncate( file->fd, result ) == -1))
{
file_set_error();
release_object( file );
......@@ -439,13 +440,13 @@ int grow_file( struct file *file, int size_high, int size_low )
set_error( ERROR_INVALID_PARAMETER );
return 0;
}
if (fstat( file->select.fd, &st ) == -1)
if (fstat( file->fd, &st ) == -1)
{
file_set_error();
return 0;
}
if (st.st_size >= size_low) return 1; /* already large enough */
if (ftruncate( file->select.fd, size_low ) != -1) return 1;
if (ftruncate( file->fd, size_low ) != -1) return 1;
file_set_error();
return 0;
}
......
......@@ -11,6 +11,7 @@
#error This file can only be used in the Wine server
#endif
#include <sys/poll.h>
#include <sys/time.h>
#include "server.h"
......@@ -89,21 +90,11 @@ extern void dump_objects(void);
/* select functions */
#define READ_EVENT 1
#define WRITE_EVENT 2
#define EXCEPT_EVENT 4
struct select_user
{
int fd; /* user fd */
void (*func)(int event, void *private); /* callback function */
void *private; /* callback private data */
};
extern void register_select_user( struct select_user *user );
extern void unregister_select_user( struct select_user *user );
extern void set_select_events( struct select_user *user, int events );
extern int check_select_events( struct select_user *user, int events );
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 check_select_events( int fd, int events );
extern void select_loop(void);
/* timeout functions */
......@@ -115,7 +106,13 @@ typedef void (*timeout_callback)( void *private );
extern struct timeout_user *add_timeout_user( struct timeval *when,
timeout_callback func, void *private );
extern void remove_timeout_user( struct timeout_user *user );
extern void make_timeout( struct timeval *when, int timeout );
extern void add_timeout( struct timeval *when, int timeout );
/* return 1 if t1 is before t2 */
static inline int time_before( struct timeval *t1, struct timeval *t2 )
{
return ((t1->tv_sec < t2->tv_sec) ||
((t1->tv_sec == t2->tv_sec) && (t1->tv_usec < t2->tv_usec)));
}
/* socket functions */
......
......@@ -33,7 +33,8 @@ struct pipe
{
struct object obj; /* object header */
struct pipe *other; /* the pipe other end */
struct select_user select; /* select user */
int fd; /* file descriptor */
int select; /* select user id */
enum side side; /* which side of the pipe is this */
};
......@@ -68,12 +69,14 @@ static struct pipe *create_pipe_side( int fd, int side )
if ((pipe = alloc_object( &pipe_ops )))
{
pipe->select.fd = fd;
pipe->select.func = default_select_event;
pipe->select.private = pipe;
pipe->other = NULL;
pipe->side = side;
register_select_user( &pipe->select );
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;
}
......@@ -111,7 +114,7 @@ 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->select.fd );
(pipe->side == READ_SIDE) ? "read" : "write", pipe->fd );
}
static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry )
......@@ -119,8 +122,7 @@ 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 */
set_select_events( &pipe->select,
(pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT );
set_select_events( pipe->select, (pipe->side == READ_SIDE) ? POLLIN : POLLOUT );
add_queue( obj, entry );
return 1;
}
......@@ -132,7 +134,7 @@ static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entr
remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */
set_select_events( &pipe->select, 0 );
set_select_events( pipe->select, 0 );
release_object( obj );
}
......@@ -142,17 +144,17 @@ static int pipe_signaled( struct object *obj, struct thread *thread )
struct pipe *pipe = (struct pipe *)obj;
assert( obj->ops == &pipe_ops );
event = (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT;
if (check_select_events( &pipe->select, event ))
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 );
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 );
if (obj->head) set_select_events( pipe->select, event );
return 0;
}
}
......@@ -172,7 +174,7 @@ static int pipe_get_read_fd( struct object *obj )
set_error( ERROR_ACCESS_DENIED );
return -1;
}
return dup( pipe->select.fd );
return dup( pipe->fd );
}
static int pipe_get_write_fd( struct object *obj )
......@@ -190,7 +192,7 @@ static int pipe_get_write_fd( struct object *obj )
set_error( ERROR_ACCESS_DENIED );
return -1;
}
return dup( pipe->select.fd );
return dup( pipe->fd );
}
static int pipe_get_info( struct object *obj, struct get_file_info_request *req )
......@@ -214,8 +216,7 @@ static void pipe_destroy( struct object *obj )
assert( obj->ops == &pipe_ops );
if (pipe->other) pipe->other->other = NULL;
unregister_select_user( &pipe->select );
close( pipe->select.fd );
remove_select_user( pipe->select );
}
/* create an anonymous pipe */
......
......@@ -39,58 +39,70 @@
static const int use_ptrace = 1; /* set to 0 to disable ptrace */
/* wait for a ptraced child to get a certain signal */
/* if the signal is 0, we simply check if anything is pending and return at once */
void wait4_thread( struct thread *thread, int signal )
/* handle a status returned by wait4 */
static int handle_child_status( struct thread *thread, int pid, int status )
{
int status;
int pid;
restart:
pid = thread ? thread->unix_pid : -1;
if ((pid = wait4( pid, &status, WUNTRACED | (signal ? 0 : WNOHANG), NULL )) == -1)
{
perror( "wait4" );
return;
}
if (WIFSTOPPED(status))
{
int sig = WSTOPSIG(status);
if (debug_level) fprintf( stderr, "ptrace: pid %d got sig %d\n", pid, sig );
if (debug_level && thread)
fprintf( stderr, "%08x: *signal* signal=%d\n", (unsigned int)thread, sig );
switch(sig)
{
case SIGSTOP: /* continue at once if not suspended */
if (!thread)
if (!(thread = get_thread_from_pid( pid ))) break;
if (!(thread->process->suspend + thread->suspend))
if (!thread || !(thread->process->suspend + thread->suspend))
ptrace( PTRACE_CONT, pid, 1, sig );
break;
default: /* ignore other signals for now */
ptrace( PTRACE_CONT, pid, 1, sig );
break;
}
if (signal && sig != signal) goto restart;
return sig;
}
else if (WIFSIGNALED(status))
if (thread && (WIFSIGNALED(status) || WIFEXITED(status)))
{
int exit_code = WTERMSIG(status);
thread->attached = 0;
thread->unix_pid = 0;
if (debug_level)
fprintf( stderr, "ptrace: pid %d killed by sig %d\n", pid, exit_code );
if (!thread)
if (!(thread = get_thread_from_pid( pid ))) return;
if (thread->client) remove_client( thread->client, exit_code );
{
if (WIFSIGNALED(status))
fprintf( stderr, "%08x: *exited* signal=%d\n",
(unsigned int)thread, WTERMSIG(status) );
else
fprintf( stderr, "%08x: *exited* status=%d\n",
(unsigned int)thread, WEXITSTATUS(status) );
}
}
else if (WIFEXITED(status))
return 0;
}
/* handle a SIGCHLD signal */
void sigchld_handler()
{
int pid, status;
for (;;)
{
int exit_code = WEXITSTATUS(status);
if (debug_level)
fprintf( stderr, "ptrace: pid %d exited with status %d\n", pid, exit_code );
if (!thread)
if (!(thread = get_thread_from_pid( pid ))) return;
if (thread->client) remove_client( thread->client, exit_code );
if (!(pid = wait4( -1, &status, WUNTRACED | WNOHANG, NULL ))) break;
if (pid != -1) handle_child_status( get_thread_from_pid(pid), pid, status );
else break;
}
else fprintf( stderr, "wait4: pid %d unknown status %x\n", pid, status );
}
/* wait for a ptraced child to get a certain signal */
void wait4_thread( struct thread *thread, int signal )
{
int res, status;
do
{
if ((res = wait4( thread->unix_pid, &status, WUNTRACED, NULL )) == -1)
{
perror( "wait4" );
return;
}
res = handle_child_status( thread, res, status );
} while (res && res != signal);
}
/* attach to a Unix thread */
......@@ -98,7 +110,7 @@ static int attach_thread( struct thread *thread )
{
/* this may fail if the client is already being debugged */
if (!use_ptrace || (ptrace( PTRACE_ATTACH, thread->unix_pid, 0, 0 ) == -1)) return 0;
if (debug_level) fprintf( stderr, "ptrace: attached to pid %d\n", thread->unix_pid );
if (debug_level) fprintf( stderr, "%08x: *attached*\n", (unsigned int)thread );
thread->attached = 1;
wait4_thread( thread, SIGSTOP );
return 1;
......@@ -113,7 +125,7 @@ void detach_thread( struct thread *thread )
if (thread->attached)
{
wait4_thread( thread, SIGTERM );
if (debug_level) fprintf( stderr, "ptrace: detaching from %d\n", thread->unix_pid );
if (debug_level) fprintf( stderr, "%08x: *detached*\n", (unsigned int)thread );
ptrace( PTRACE_DETACH, thread->unix_pid, 1, SIGTERM );
thread->attached = 0;
}
......
......@@ -32,7 +32,8 @@
/* client structure */
struct client
{
struct select_user select; /* select user */
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) */
......@@ -62,7 +63,7 @@ static int do_write( struct client *client )
if (client->pass_fd == -1)
{
ret = write( client->select.fd, &client->res, sizeof(client->res) );
ret = write( client->fd, &client->res, sizeof(client->res) );
if (ret == sizeof(client->res)) goto ok;
}
else /* we have an fd to send */
......@@ -79,7 +80,7 @@ static int do_write( struct client *client )
myiovec.iov_base = (void *)&client->res;
myiovec.iov_len = sizeof(client->res);
ret = sendmsg( client->select.fd, &msghdr, 0 );
ret = sendmsg( client->fd, &msghdr, 0 );
close( client->pass_fd );
client->pass_fd = -1;
if (ret == sizeof(client->res)) goto ok;
......@@ -91,10 +92,10 @@ static int do_write( struct client *client )
}
else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(client->res) );
remove_client( client, BROKEN_PIPE );
return 0;
return -1;
ok:
set_select_events( &client->select, READ_EVENT );
set_select_events( client->select, POLLIN );
return 1;
}
......@@ -119,7 +120,7 @@ static void do_read( struct client *client )
myiovec.iov_base = (void *)&req;
myiovec.iov_len = sizeof(req);
ret = recvmsg( client->select.fd, &msghdr, 0 );
ret = recvmsg( client->fd, &msghdr, 0 );
#ifndef HAVE_MSGHDR_ACCRIGHTS
client->pass_fd = cmsg.fd;
#endif
......@@ -150,8 +151,12 @@ static void do_read( struct client *client )
static void client_event( int event, void *private )
{
struct client *client = (struct client *)private;
if (event & WRITE_EVENT) do_write( client );
if (event & READ_EVENT) do_read( client );
if (event & (POLLERR | POLLHUP)) remove_client( client, BROKEN_PIPE );
else
{
if (event & POLLOUT) do_write( client );
if (event & POLLIN) do_read( client );
}
}
/*******************************************************************/
......@@ -167,14 +172,16 @@ struct client *add_client( int fd, struct thread *self )
flags = fcntl( fd, F_GETFL, 0 );
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
client->select.fd = fd;
client->select.func = client_event;
client->select.private = client;
client->self = self;
client->timeout = NULL;
client->pass_fd = -1;
register_select_user( &client->select );
set_select_events( &client->select, READ_EVENT );
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;
}
......@@ -186,8 +193,7 @@ void remove_client( struct client *client, int exit_code )
call_kill_handler( client->self, exit_code );
if (client->timeout) remove_timeout_user( client->timeout );
unregister_select_user( &client->select );
close( client->select.fd );
remove_select_user( client->select );
/* Purge messages */
if (client->pass_fd != -1) close( client->pass_fd );
......@@ -206,5 +212,5 @@ 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, WRITE_EVENT );
if (!do_write( client )) set_select_events( client->select, POLLOUT );
}
......@@ -330,7 +330,11 @@ static int wait_on( struct thread *thread, int count,
wait->count = count;
wait->flags = flags;
wait->user = NULL;
if (flags & SELECT_TIMEOUT) make_timeout( &wait->timeout, timeout );
if (flags & SELECT_TIMEOUT)
{
gettimeofday( &wait->timeout, 0 );
add_timeout( &wait->timeout, timeout );
}
for (i = 0, entry = wait->queues; i < count; i++, entry++)
{
......@@ -399,9 +403,7 @@ static int check_wait( struct thread *thread, int *signaled )
{
struct timeval now;
gettimeofday( &now, NULL );
if ((now.tv_sec > wait->timeout.tv_sec) ||
((now.tv_sec == wait->timeout.tv_sec) &&
(now.tv_usec >= wait->timeout.tv_usec)))
if (!time_before( &now, &wait->timeout ))
{
*signaled = STATUS_TIMEOUT;
return 1;
......
......@@ -80,7 +80,8 @@ extern void wake_up( struct object *obj, int max );
/* ptrace functions */
extern void wait4_thread( struct thread *thread, int wait );
extern void sigchld_handler();
extern void wait4_thread( struct thread *thread, int signal );
extern void stop_thread( struct thread *thread );
extern void continue_thread( struct thread *thread );
extern void detach_thread( struct thread *thread );
......
......@@ -81,7 +81,7 @@ static void timer_callback( void *private )
if (timer->period) /* schedule the next expiration */
{
make_timeout( &timer->when, timer->period );
add_timeout( &timer->when, timer->period );
timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
}
else timer->timeout = NULL;
......@@ -101,8 +101,17 @@ static void set_timer( struct timer *timer, int sec, int usec, int period,
timer->signaled = 0;
}
if (timer->timeout) remove_timeout_user( timer->timeout );
timer->when.tv_sec = sec;
timer->when.tv_usec = usec;
if (!sec && !usec)
{
/* special case: use now + period as first expiration */
gettimeofday( &timer->when, 0 );
add_timeout( &timer->when, period );
}
else
{
timer->when.tv_sec = sec;
timer->when.tv_usec = usec;
}
timer->period = period;
timer->callback = callback;
timer->arg = arg;
......
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