forked from Mirrors/wine-wine
Made sleep_on usable from all requests.
parent
282377824d
commit
9de03f4f6a
|
@ -76,23 +76,13 @@ static void call_req_handler( struct thread *thread, enum request req, int fd )
|
||||||
if (req < REQ_NB_REQUESTS)
|
if (req < REQ_NB_REQUESTS)
|
||||||
{
|
{
|
||||||
req_handlers[req].handler( current->buffer, fd );
|
req_handlers[req].handler( current->buffer, fd );
|
||||||
if (current && current->state != SLEEPING) send_reply( current );
|
if (current && !current->wait) send_reply( current );
|
||||||
current = NULL;
|
current = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fatal_protocol_error( current, "bad request %d\n", req );
|
fatal_protocol_error( current, "bad request %d\n", req );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle a client timeout */
|
|
||||||
void call_timeout_handler( void *thread )
|
|
||||||
{
|
|
||||||
current = (struct thread *)thread;
|
|
||||||
if (debug_level) trace_timeout();
|
|
||||||
clear_error();
|
|
||||||
thread_timeout();
|
|
||||||
current = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the fd to pass to the thread */
|
/* set the fd to pass to the thread */
|
||||||
void set_reply_fd( struct thread *thread, int pass_fd )
|
void set_reply_fd( struct thread *thread, int pass_fd )
|
||||||
{
|
{
|
||||||
|
@ -103,7 +93,7 @@ void set_reply_fd( struct thread *thread, int pass_fd )
|
||||||
/* send a reply to a thread */
|
/* send a reply to a thread */
|
||||||
void send_reply( struct thread *thread )
|
void send_reply( struct thread *thread )
|
||||||
{
|
{
|
||||||
if (thread->state == SLEEPING) thread->state = RUNNING;
|
assert( !thread->wait );
|
||||||
if (debug_level) trace_reply( thread );
|
if (debug_level) trace_reply( thread );
|
||||||
if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT );
|
if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT );
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,10 @@
|
||||||
extern void read_request( struct thread *thread );
|
extern void read_request( struct thread *thread );
|
||||||
extern int write_request( struct thread *thread );
|
extern int write_request( struct thread *thread );
|
||||||
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
||||||
extern void call_timeout_handler( void *thread );
|
|
||||||
extern void set_reply_fd( struct thread *thread, int pass_fd );
|
extern void set_reply_fd( struct thread *thread, int pass_fd );
|
||||||
extern void send_reply( struct thread *thread );
|
extern void send_reply( struct thread *thread );
|
||||||
|
|
||||||
extern void trace_request( enum request req, int fd );
|
extern void trace_request( enum request req, int fd );
|
||||||
extern void trace_timeout(void);
|
|
||||||
extern void trace_kill( struct thread *thread );
|
extern void trace_kill( struct thread *thread );
|
||||||
extern void trace_reply( struct thread *thread );
|
extern void trace_reply( struct thread *thread );
|
||||||
|
|
||||||
|
|
147
server/thread.c
147
server/thread.c
|
@ -46,6 +46,7 @@ struct thread_wait
|
||||||
int flags;
|
int flags;
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
struct timeout_user *user;
|
struct timeout_user *user;
|
||||||
|
sleep_reply reply; /* function to build the reply */
|
||||||
struct wait_queue_entry queues[1];
|
struct wait_queue_entry queues[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,8 +118,6 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
|
||||||
thread->teb = NULL;
|
thread->teb = NULL;
|
||||||
thread->mutex = NULL;
|
thread->mutex = NULL;
|
||||||
thread->debug_ctx = NULL;
|
thread->debug_ctx = NULL;
|
||||||
thread->debug_event = NULL;
|
|
||||||
thread->exit_event = NULL;
|
|
||||||
thread->wait = NULL;
|
thread->wait = NULL;
|
||||||
thread->apc = NULL;
|
thread->apc = NULL;
|
||||||
thread->apc_count = 0;
|
thread->apc_count = 0;
|
||||||
|
@ -330,24 +329,19 @@ static void end_wait( struct thread *thread )
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build the thread wait structure */
|
/* build the thread wait structure */
|
||||||
static int wait_on( struct thread *thread, int count,
|
static int wait_on( int count, struct object *objects[], int flags,
|
||||||
int *handles, int flags, int timeout )
|
int timeout, sleep_reply func )
|
||||||
{
|
{
|
||||||
struct thread_wait *wait;
|
struct thread_wait *wait;
|
||||||
struct wait_queue_entry *entry;
|
struct wait_queue_entry *entry;
|
||||||
struct object *obj;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS))
|
|
||||||
{
|
|
||||||
set_error( ERROR_INVALID_PARAMETER );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!(wait = mem_alloc( sizeof(*wait) + (count-1) * sizeof(*entry) ))) return 0;
|
if (!(wait = mem_alloc( sizeof(*wait) + (count-1) * sizeof(*entry) ))) return 0;
|
||||||
thread->wait = wait;
|
current->wait = wait;
|
||||||
wait->count = count;
|
wait->count = count;
|
||||||
wait->flags = flags;
|
wait->flags = flags;
|
||||||
wait->user = NULL;
|
wait->user = NULL;
|
||||||
|
wait->reply = func;
|
||||||
if (flags & SELECT_TIMEOUT)
|
if (flags & SELECT_TIMEOUT)
|
||||||
{
|
{
|
||||||
gettimeofday( &wait->timeout, 0 );
|
gettimeofday( &wait->timeout, 0 );
|
||||||
|
@ -356,33 +350,27 @@ static int wait_on( struct thread *thread, int count,
|
||||||
|
|
||||||
for (i = 0, entry = wait->queues; i < count; i++, entry++)
|
for (i = 0, entry = wait->queues; i < count; i++, entry++)
|
||||||
{
|
{
|
||||||
if (!(obj = get_handle_obj( thread->process, handles[i],
|
struct object *obj = objects[i];
|
||||||
SYNCHRONIZE, NULL )))
|
entry->thread = current;
|
||||||
{
|
|
||||||
wait->count = i - 1;
|
|
||||||
end_wait( thread );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
entry->thread = thread;
|
|
||||||
if (!obj->ops->add_queue( obj, entry ))
|
if (!obj->ops->add_queue( obj, entry ))
|
||||||
{
|
{
|
||||||
wait->count = i - 1;
|
wait->count = i;
|
||||||
end_wait( thread );
|
end_wait( current );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
release_object( obj );
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if the thread waiting condition is satisfied */
|
/* check if the thread waiting condition is satisfied */
|
||||||
static int check_wait( struct thread *thread, int *signaled )
|
static int check_wait( struct thread *thread, struct object **object )
|
||||||
{
|
{
|
||||||
int i;
|
int i, signaled;
|
||||||
struct thread_wait *wait = thread->wait;
|
struct thread_wait *wait = thread->wait;
|
||||||
struct wait_queue_entry *entry = wait->queues;
|
struct wait_queue_entry *entry = wait->queues;
|
||||||
|
|
||||||
assert( wait );
|
assert( wait );
|
||||||
|
*object = NULL;
|
||||||
if (wait->flags & SELECT_ALL)
|
if (wait->flags & SELECT_ALL)
|
||||||
{
|
{
|
||||||
int not_ok = 0;
|
int not_ok = 0;
|
||||||
|
@ -392,11 +380,11 @@ static int check_wait( struct thread *thread, int *signaled )
|
||||||
not_ok |= !entry->obj->ops->signaled( entry->obj, thread );
|
not_ok |= !entry->obj->ops->signaled( entry->obj, thread );
|
||||||
if (not_ok) goto other_checks;
|
if (not_ok) goto other_checks;
|
||||||
/* Wait satisfied: tell it to all objects */
|
/* Wait satisfied: tell it to all objects */
|
||||||
*signaled = 0;
|
signaled = 0;
|
||||||
for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
|
for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
|
||||||
if (entry->obj->ops->satisfied( entry->obj, thread ))
|
if (entry->obj->ops->satisfied( entry->obj, thread ))
|
||||||
*signaled = STATUS_ABANDONED_WAIT_0;
|
signaled = STATUS_ABANDONED_WAIT_0;
|
||||||
return 1;
|
return signaled;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -404,75 +392,97 @@ static int check_wait( struct thread *thread, int *signaled )
|
||||||
{
|
{
|
||||||
if (!entry->obj->ops->signaled( entry->obj, thread )) continue;
|
if (!entry->obj->ops->signaled( entry->obj, thread )) continue;
|
||||||
/* Wait satisfied: tell it to the object */
|
/* Wait satisfied: tell it to the object */
|
||||||
*signaled = i;
|
signaled = i;
|
||||||
|
*object = entry->obj;
|
||||||
if (entry->obj->ops->satisfied( entry->obj, thread ))
|
if (entry->obj->ops->satisfied( entry->obj, thread ))
|
||||||
*signaled = i + STATUS_ABANDONED_WAIT_0;
|
signaled = i + STATUS_ABANDONED_WAIT_0;
|
||||||
return 1;
|
return signaled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
other_checks:
|
other_checks:
|
||||||
if ((wait->flags & SELECT_ALERTABLE) && thread->apc)
|
if ((wait->flags & SELECT_ALERTABLE) && thread->apc) return STATUS_USER_APC;
|
||||||
{
|
|
||||||
*signaled = STATUS_USER_APC;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (wait->flags & SELECT_TIMEOUT)
|
if (wait->flags & SELECT_TIMEOUT)
|
||||||
{
|
{
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
gettimeofday( &now, NULL );
|
gettimeofday( &now, NULL );
|
||||||
if (!time_before( &now, &wait->timeout ))
|
if (!time_before( &now, &wait->timeout )) return STATUS_TIMEOUT;
|
||||||
{
|
|
||||||
*signaled = STATUS_TIMEOUT;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build a reply to the select request */
|
||||||
|
static void build_select_reply( struct thread *thread, struct object *obj, int signaled )
|
||||||
|
{
|
||||||
|
struct select_request *req = get_req_ptr( thread );
|
||||||
|
req->signaled = signaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* attempt to wake up a thread */
|
/* attempt to wake up a thread */
|
||||||
/* return 1 if OK, 0 if the wait condition is still not satisfied */
|
/* return 1 if OK, 0 if the wait condition is still not satisfied */
|
||||||
static int wake_thread( struct thread *thread )
|
static int wake_thread( struct thread *thread )
|
||||||
{
|
{
|
||||||
struct select_request *req = get_req_ptr( thread );
|
int signaled;
|
||||||
|
struct object *object;
|
||||||
if (!check_wait( thread, &req->signaled )) return 0;
|
if ((signaled = check_wait( thread, &object )) == -1) return 0;
|
||||||
|
thread->error = 0;
|
||||||
|
thread->wait->reply( thread, object, signaled );
|
||||||
end_wait( thread );
|
end_wait( thread );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sleep on a list of objects */
|
/* thread wait timeout */
|
||||||
static void sleep_on( struct thread *thread, int count, int *handles, int flags, int timeout )
|
static void thread_timeout( void *ptr )
|
||||||
{
|
{
|
||||||
struct select_request *req;
|
struct thread *thread = ptr;
|
||||||
assert( !thread->wait );
|
if (debug_level) fprintf( stderr, "%08x: *timeout*\n", (unsigned int)thread );
|
||||||
if (!wait_on( thread, count, handles, flags, timeout )) goto error;
|
assert( thread->wait );
|
||||||
if (wake_thread( thread )) return;
|
thread->error = 0;
|
||||||
|
thread->wait->user = NULL;
|
||||||
|
thread->wait->reply( thread, NULL, STATUS_TIMEOUT );
|
||||||
|
end_wait( thread );
|
||||||
|
send_reply( thread );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sleep on a list of objects */
|
||||||
|
int sleep_on( int count, struct object *objects[], int flags, int timeout, sleep_reply func )
|
||||||
|
{
|
||||||
|
assert( !current->wait );
|
||||||
|
if (!wait_on( count, objects, flags, timeout, func )) return 0;
|
||||||
|
if (wake_thread( current )) return 1;
|
||||||
/* now we need to wait */
|
/* now we need to wait */
|
||||||
if (flags & SELECT_TIMEOUT)
|
if (flags & SELECT_TIMEOUT)
|
||||||
{
|
{
|
||||||
if (!(thread->wait->user = add_timeout_user( &thread->wait->timeout,
|
if (!(current->wait->user = add_timeout_user( ¤t->wait->timeout,
|
||||||
call_timeout_handler, thread )))
|
thread_timeout, current )))
|
||||||
goto error;
|
{
|
||||||
|
end_wait( current );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
thread->state = SLEEPING;
|
return 1;
|
||||||
return;
|
|
||||||
|
|
||||||
error:
|
|
||||||
req = get_req_ptr( thread );
|
|
||||||
req->signaled = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* timeout for the current thread */
|
/* select on a list of handles */
|
||||||
void thread_timeout(void)
|
static int select_on( int count, int *handles, int flags, int timeout )
|
||||||
{
|
{
|
||||||
struct select_request *req = get_req_ptr( current );
|
int ret = 0;
|
||||||
|
int i;
|
||||||
|
struct object *objects[MAXIMUM_WAIT_OBJECTS];
|
||||||
|
|
||||||
assert( current->wait );
|
if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS))
|
||||||
current->wait->user = NULL;
|
{
|
||||||
end_wait( current );
|
set_error( ERROR_INVALID_PARAMETER );
|
||||||
req->signaled = STATUS_TIMEOUT;
|
return 0;
|
||||||
send_reply( current );
|
}
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL )))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == count) ret = sleep_on( count, objects, flags, timeout, build_select_reply );
|
||||||
|
while (--i >= 0) release_object( objects[i] );
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* attempt to wake threads sleeping on the object wait queue */
|
/* attempt to wake threads sleeping on the object wait queue */
|
||||||
|
@ -642,7 +652,8 @@ DECL_HANDLER(resume_thread)
|
||||||
/* select on a handle list */
|
/* select on a handle list */
|
||||||
DECL_HANDLER(select)
|
DECL_HANDLER(select)
|
||||||
{
|
{
|
||||||
sleep_on( current, req->count, req->handles, req->flags, req->timeout );
|
if (!select_on( req->count, req->handles, req->flags, req->timeout ))
|
||||||
|
req->signaled = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* queue an APC for a thread */
|
/* queue an APC for a thread */
|
||||||
|
|
|
@ -20,12 +20,10 @@ struct thread_wait;
|
||||||
struct thread_apc;
|
struct thread_apc;
|
||||||
struct mutex;
|
struct mutex;
|
||||||
struct debug_ctx;
|
struct debug_ctx;
|
||||||
struct debug_event;
|
|
||||||
|
|
||||||
enum run_state
|
enum run_state
|
||||||
{
|
{
|
||||||
RUNNING, /* running normally */
|
RUNNING, /* running normally */
|
||||||
SLEEPING, /* sleeping waiting for a request to terminate */
|
|
||||||
TERMINATED /* terminated */
|
TERMINATED /* terminated */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,8 +38,6 @@ struct thread
|
||||||
struct process *process;
|
struct process *process;
|
||||||
struct mutex *mutex; /* list of currently owned mutexes */
|
struct mutex *mutex; /* list of currently owned mutexes */
|
||||||
struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */
|
struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */
|
||||||
struct debug_event *debug_event; /* pending debug event for this thread */
|
|
||||||
struct debug_event *exit_event; /* pending debug exit event for this thread */
|
|
||||||
struct thread_wait *wait; /* current wait condition if sleeping */
|
struct thread_wait *wait; /* current wait condition if sleeping */
|
||||||
struct thread_apc *apc; /* list of async procedure calls */
|
struct thread_apc *apc; /* list of async procedure calls */
|
||||||
int apc_count; /* number of outstanding APCs */
|
int apc_count; /* number of outstanding APCs */
|
||||||
|
@ -59,6 +55,9 @@ struct thread
|
||||||
enum request last_req; /* last request received (for debugging) */
|
enum request last_req; /* last request received (for debugging) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* callback function for building the thread reply when sleep_on is finished */
|
||||||
|
typedef void (*sleep_reply)( struct thread *thread, struct object *obj, int signaled );
|
||||||
|
|
||||||
extern struct thread *current;
|
extern struct thread *current;
|
||||||
|
|
||||||
/* thread functions */
|
/* thread functions */
|
||||||
|
@ -74,8 +73,9 @@ extern void resume_all_threads( void );
|
||||||
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
|
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 remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
extern void kill_thread( struct thread *thread, int exit_code );
|
extern void kill_thread( struct thread *thread, int exit_code );
|
||||||
extern void thread_timeout(void);
|
|
||||||
extern void wake_up( struct object *obj, int max );
|
extern void wake_up( struct object *obj, int max );
|
||||||
|
extern int sleep_on( int count, struct object *objects[], int flags,
|
||||||
|
int timeout, sleep_reply func );
|
||||||
|
|
||||||
/* ptrace functions */
|
/* ptrace functions */
|
||||||
|
|
||||||
|
|
|
@ -1336,11 +1336,6 @@ void trace_request( enum request req, int fd )
|
||||||
else fprintf( stderr, " )\n" );
|
else fprintf( stderr, " )\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_timeout(void)
|
|
||||||
{
|
|
||||||
fprintf( stderr, "%08x: *timeout*\n", (unsigned int)current );
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace_kill( struct thread *thread )
|
void trace_kill( struct thread *thread )
|
||||||
{
|
{
|
||||||
fprintf( stderr,"%08x: *killed* exit_code=%d\n",
|
fprintf( stderr,"%08x: *killed* exit_code=%d\n",
|
||||||
|
|
Loading…
Reference in New Issue