Added separate server pipe to wait on blocking server calls.
Send the complete request/reply through the request fifo instead of
just a dummy byte.
Convert error status to text in server reply tracing.
diff --git a/server/thread.c b/server/thread.c
index 31e3ff0..301c3b0 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -40,7 +40,6 @@
int flags;
struct timeval timeout;
struct timeout_user *user;
- sleep_reply reply; /* function to build the reply */
struct wait_queue_entry queues[1];
};
@@ -88,14 +87,16 @@
/* allocate the buffer for the communication with the client */
static int alloc_client_buffer( struct thread *thread )
{
- struct get_thread_buffer_request *req;
- int fd, fd_pipe[2];
+ union generic_request *req;
+ int fd = -1, fd_pipe[2], wait_pipe[2];
+ wait_pipe[0] = wait_pipe[1] = -1;
if (pipe( fd_pipe ) == -1)
{
file_set_error();
return 0;
}
+ if (pipe( wait_pipe ) == -1) goto error;
if ((fd = create_anonymous_file()) == -1) goto error;
if (ftruncate( fd, MAX_REQUEST_LENGTH ) == -1) goto error;
if ((thread->buffer = mmap( 0, MAX_REQUEST_LENGTH, PROT_READ | PROT_WRITE,
@@ -103,21 +104,30 @@
thread->buffer_info = (struct server_buffer_info *)((char *)thread->buffer + MAX_REQUEST_LENGTH) - 1;
if (!(thread->request_fd = create_request_socket( thread ))) goto error;
thread->reply_fd = fd_pipe[1];
+ thread->wait_fd = wait_pipe[1];
+
+ /* make the pipes non-blocking */
+ fcntl( fd_pipe[1], F_SETFL, O_NONBLOCK );
+ fcntl( wait_pipe[1], F_SETFL, O_NONBLOCK );
+
/* build the first request into the buffer and send it */
req = thread->buffer;
- req->pid = get_process_id( thread->process );
- req->tid = get_thread_id( thread );
- req->boot = (thread == booting_thread);
- req->version = SERVER_PROTOCOL_VERSION;
+ req->get_thread_buffer.pid = get_process_id( thread->process );
+ req->get_thread_buffer.tid = get_thread_id( thread );
+ req->get_thread_buffer.boot = (thread == booting_thread);
+ req->get_thread_buffer.version = SERVER_PROTOCOL_VERSION;
/* add it here since send_client_fd may call kill_thread */
add_process_thread( thread->process, thread );
send_client_fd( thread, fd_pipe[0], 0 );
+ send_client_fd( thread, wait_pipe[0], 0 );
send_client_fd( thread, fd, 0 );
- send_reply( thread );
+ send_reply( thread, req );
close( fd_pipe[0] );
+ close( wait_pipe[0] );
close( fd );
+
return 1;
error:
@@ -125,6 +135,8 @@
if (fd != -1) close( fd );
close( fd_pipe[0] );
close( fd_pipe[1] );
+ if (wait_pipe[0] != -1) close( wait_pipe[0] );
+ if (wait_pipe[1] != -1) close( wait_pipe[1] );
return 0;
}
@@ -155,6 +167,7 @@
thread->pass_fd = -1;
thread->request_fd = NULL;
thread->reply_fd = -1;
+ thread->wait_fd = -1;
thread->state = RUNNING;
thread->attached = 0;
thread->exit_code = 0;
@@ -194,11 +207,7 @@
assert( obj->ops == &thread_ops );
if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 );
- else
- {
- if (event & POLLOUT) write_request( thread );
- if (event & POLLIN) read_request( thread );
- }
+ else if (event & POLLIN) read_request( thread );
}
/* destroy a thread when its refcount is 0 */
@@ -218,6 +227,7 @@
if (thread->queue) release_object( thread->queue );
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
if (thread->reply_fd != -1) close( thread->reply_fd );
+ if (thread->wait_fd != -1) close( thread->wait_fd );
if (thread->pass_fd != -1) close( thread->pass_fd );
if (thread->request_fd) release_object( thread->request_fd );
}
@@ -355,8 +365,7 @@
}
/* build the thread wait structure */
-static int wait_on( int count, struct object *objects[], int flags,
- int sec, int usec, sleep_reply func )
+static int wait_on( int count, struct object *objects[], int flags, int sec, int usec )
{
struct thread_wait *wait;
struct wait_queue_entry *entry;
@@ -367,7 +376,6 @@
wait->count = count;
wait->flags = flags;
wait->user = NULL;
- wait->reply = func;
if (flags & SELECT_TIMEOUT)
{
wait->timeout.tv_sec = sec;
@@ -389,14 +397,13 @@
}
/* check if the thread waiting condition is satisfied */
-static int check_wait( struct thread *thread, struct object **object )
+static int check_wait( struct thread *thread )
{
int i, signaled;
struct thread_wait *wait = thread->wait;
struct wait_queue_entry *entry = wait->queues;
assert( wait );
- *object = NULL;
if (wait->flags & SELECT_ALL)
{
int not_ok = 0;
@@ -419,7 +426,6 @@
if (!entry->obj->ops->signaled( entry->obj, thread )) continue;
/* Wait satisfied: tell it to the object */
signaled = i;
- *object = entry->obj;
if (entry->obj->ops->satisfied( entry->obj, thread ))
signaled = i + STATUS_ABANDONED_WAIT_0;
return signaled;
@@ -438,23 +444,17 @@
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 */
/* return 1 if OK, 0 if the wait condition is still not satisfied */
static int wake_thread( struct thread *thread )
{
int signaled;
- struct object *object;
- if ((signaled = check_wait( thread, &object )) == -1) return 0;
- thread->error = 0;
- thread->wait->reply( thread, object, signaled );
+ if ((signaled = check_wait( thread )) == -1) return 0;
+
+ if (debug_level) fprintf( stderr, "%08x: *wakeup* object=%d\n",
+ (unsigned int)thread, signaled );
end_wait( thread );
+ send_thread_wakeup( thread, signaled );
return 1;
}
@@ -462,21 +462,45 @@
static void thread_timeout( void *ptr )
{
struct thread *thread = ptr;
+
if (debug_level) fprintf( stderr, "%08x: *timeout*\n", (unsigned int)thread );
+
assert( thread->wait );
- thread->error = 0;
thread->wait->user = NULL;
- thread->wait->reply( thread, NULL, STATUS_TIMEOUT );
end_wait( thread );
- send_reply( thread );
+ send_thread_wakeup( thread, STATUS_TIMEOUT );
}
-/* sleep on a list of objects */
-int sleep_on( int count, struct object *objects[], int flags, int sec, int usec, sleep_reply func )
+/* select on a list of handles */
+static void select_on( int count, handle_t *handles, int flags, int sec, int usec )
{
+ int ret, i;
+ struct object *objects[MAXIMUM_WAIT_OBJECTS];
+
assert( !current->wait );
- if (!wait_on( count, objects, flags, sec, usec, func )) return 0;
- if (wake_thread( current )) return 1;
+
+ if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+ for (i = 0; i < count; i++)
+ {
+ if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL )))
+ break;
+ }
+
+ if (i < count) goto done;
+ if (!wait_on( count, objects, flags, sec, usec )) goto done;
+
+ if ((ret = check_wait( current )) != -1)
+ {
+ /* condition is already satisfied */
+ end_wait( current );
+ set_error( ret );
+ goto done;
+ }
+
/* now we need to wait */
if (flags & SELECT_TIMEOUT)
{
@@ -484,32 +508,13 @@
thread_timeout, current )))
{
end_wait( current );
- return 0;
+ goto done;
}
}
- return 1;
-}
+ set_error( STATUS_PENDING );
-/* select on a list of handles */
-static int select_on( int count, handle_t *handles, int flags, int sec, int usec )
-{
- int ret = 0;
- int i;
- struct object *objects[MAXIMUM_WAIT_OBJECTS];
-
- if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS))
- {
- set_error( STATUS_INVALID_PARAMETER );
- return 0;
- }
- 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, sec, usec, build_select_reply );
+done:
while (--i >= 0) release_object( objects[i] );
- return ret;
}
/* attempt to wake threads sleeping on the object wait queue */
@@ -523,7 +528,6 @@
entry = entry->next;
if (wake_thread( thread ))
{
- send_reply( thread );
if (max && !--max) break;
}
}
@@ -558,7 +562,7 @@
if (!apc->prev) /* first one */
{
queue->head = apc;
- if (thread->wait && wake_thread( thread )) send_reply( thread );
+ if (thread->wait) wake_thread( thread );
}
return 1;
}
@@ -648,9 +652,11 @@
remove_select_user( &thread->obj );
release_object( thread->request_fd );
close( thread->reply_fd );
+ close( thread->wait_fd );
munmap( thread->buffer, MAX_REQUEST_LENGTH );
thread->request_fd = NULL;
thread->reply_fd = -1;
+ thread->wait_fd = -1;
thread->buffer = (void *)-1;
release_object( thread );
}
@@ -819,8 +825,7 @@
DECL_HANDLER(select)
{
int count = get_req_data_size(req) / sizeof(int);
- if (!select_on( count, get_req_data(req), req->flags, req->sec, req->usec ))
- req->signaled = -1;
+ select_on( count, get_req_data(req), req->flags, req->sec, req->usec );
}
/* queue an APC for a thread */