Moved poll handling to the generic part of the server objects.
Fixed busy waiting on POLLERR events.
Merged struct client into struct thread.
diff --git a/server/object.c b/server/object.c
index 9d44965..28cfe67 100644
--- a/server/object.c
+++ b/server/object.c
@@ -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 @@
}
/* 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 @@
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 @@
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 @@
/* 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 @@
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 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 )
{
- struct object *obj = (struct object *)private;
- assert( obj );
+ 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 )
+{
+ /* an error occurred, stop polling this fd to avoid busy-looping */
+ if (event & (POLLERR | POLLHUP)) set_select_events( obj, -1 );
wake_up( obj, 0 );
}