Moved all references to file descriptors out of the generic object
structure. Changed the poll()-related routines to deal with file descriptors instead of objects and integrated poll support into fd.c.
This commit is contained in:
parent
ac13d2f47e
commit
e66207ebfc
@ -31,7 +31,6 @@ C_SRCS = \
|
|||||||
queue.c \
|
queue.c \
|
||||||
registry.c \
|
registry.c \
|
||||||
request.c \
|
request.c \
|
||||||
select.c \
|
|
||||||
semaphore.c \
|
semaphore.c \
|
||||||
serial.c \
|
serial.c \
|
||||||
smb.c \
|
smb.c \
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
|
#include "file.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ static struct atom_table *create_table(int entries_count)
|
|||||||
{
|
{
|
||||||
struct atom_table *table;
|
struct atom_table *table;
|
||||||
|
|
||||||
if ((table = alloc_object( &atom_table_ops, -1 )))
|
if ((table = alloc_object( &atom_table_ops )))
|
||||||
{
|
{
|
||||||
if ((entries_count < MIN_HASH_SIZE) ||
|
if ((entries_count < MIN_HASH_SIZE) ||
|
||||||
(entries_count > MAX_HASH_SIZE)) entries_count = HASH_SIZE;
|
(entries_count > MAX_HASH_SIZE)) entries_count = HASH_SIZE;
|
||||||
|
@ -54,7 +54,7 @@ static const struct object_ops change_ops =
|
|||||||
static struct change *create_change_notification( int subtree, int filter )
|
static struct change *create_change_notification( int subtree, int filter )
|
||||||
{
|
{
|
||||||
struct change *change;
|
struct change *change;
|
||||||
if ((change = alloc_object( &change_ops, -1 )))
|
if ((change = alloc_object( &change_ops )))
|
||||||
{
|
{
|
||||||
change->subtree = subtree;
|
change->subtree = subtree;
|
||||||
change->filter = filter;
|
change->filter = filter;
|
||||||
|
@ -199,7 +199,7 @@ static struct console_input_events *create_console_input_events(void)
|
|||||||
{
|
{
|
||||||
struct console_input_events* evt;
|
struct console_input_events* evt;
|
||||||
|
|
||||||
if (!(evt = alloc_object( &console_input_events_ops, -1 ))) return NULL;
|
if (!(evt = alloc_object( &console_input_events_ops ))) return NULL;
|
||||||
evt->num_alloc = evt->num_used = 0;
|
evt->num_alloc = evt->num_used = 0;
|
||||||
evt->events = NULL;
|
evt->events = NULL;
|
||||||
return evt;
|
return evt;
|
||||||
@ -209,7 +209,7 @@ static struct object *create_console_input( struct thread* renderer )
|
|||||||
{
|
{
|
||||||
struct console_input *console_input;
|
struct console_input *console_input;
|
||||||
|
|
||||||
if (!(console_input = alloc_object( &console_input_ops, -1 ))) return NULL;
|
if (!(console_input = alloc_object( &console_input_ops ))) return NULL;
|
||||||
console_input->renderer = renderer;
|
console_input->renderer = renderer;
|
||||||
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
|
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
|
||||||
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
|
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
|
||||||
@ -239,7 +239,7 @@ static struct screen_buffer *create_console_output( struct console_input *consol
|
|||||||
struct console_renderer_event evt;
|
struct console_renderer_event evt;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!(screen_buffer = alloc_object( &screen_buffer_ops, -1 ))) return NULL;
|
if (!(screen_buffer = alloc_object( &screen_buffer_ops ))) return NULL;
|
||||||
screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
|
screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
|
||||||
screen_buffer->input = console_input;
|
screen_buffer->input = console_input;
|
||||||
screen_buffer->cursor_size = 100;
|
screen_buffer->cursor_size = 100;
|
||||||
|
@ -374,7 +374,7 @@ static struct debug_event *alloc_debug_event( struct thread *thread, int code,
|
|||||||
assert( debugger->process != thread->process );
|
assert( debugger->process != thread->process );
|
||||||
|
|
||||||
/* build the event */
|
/* build the event */
|
||||||
if (!(event = alloc_object( &debug_event_ops, -1 ))) return NULL;
|
if (!(event = alloc_object( &debug_event_ops ))) return NULL;
|
||||||
event->next = NULL;
|
event->next = NULL;
|
||||||
event->prev = NULL;
|
event->prev = NULL;
|
||||||
event->state = EVENT_QUEUED;
|
event->state = EVENT_QUEUED;
|
||||||
@ -537,7 +537,7 @@ int set_process_debugger( struct process *process, struct thread *debugger )
|
|||||||
|
|
||||||
if (!debugger->debug_ctx) /* need to allocate a context */
|
if (!debugger->debug_ctx) /* need to allocate a context */
|
||||||
{
|
{
|
||||||
if (!(debug_ctx = alloc_object( &debug_ctx_ops, -1 ))) return 0;
|
if (!(debug_ctx = alloc_object( &debug_ctx_ops ))) return 0;
|
||||||
debug_ctx->event_head = NULL;
|
debug_ctx->event_head = NULL;
|
||||||
debug_ctx->event_tail = NULL;
|
debug_ctx->event_tail = NULL;
|
||||||
debug_ctx->kill_on_exit = 1;
|
debug_ctx->kill_on_exit = 1;
|
||||||
|
@ -59,7 +59,7 @@ static const struct object_ops device_ops =
|
|||||||
static struct device *create_device( int id )
|
static struct device *create_device( int id )
|
||||||
{
|
{
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
if ((dev = alloc_object( &device_ops, -1 )))
|
if ((dev = alloc_object( &device_ops )))
|
||||||
{
|
{
|
||||||
dev->id = id;
|
dev->id = id;
|
||||||
}
|
}
|
||||||
|
363
server/fd.c
363
server/fd.c
@ -22,9 +22,15 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#ifdef HAVE_SYS_POLL_H
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
@ -40,6 +46,7 @@ struct fd
|
|||||||
const struct fd_ops *fd_ops; /* file descriptor operations */
|
const struct fd_ops *fd_ops; /* file descriptor operations */
|
||||||
struct object *user; /* object using this file descriptor */
|
struct object *user; /* object using this file descriptor */
|
||||||
int unix_fd; /* unix file descriptor */
|
int unix_fd; /* unix file descriptor */
|
||||||
|
int poll_index; /* index of fd in poll array */
|
||||||
int mode; /* file protection mode */
|
int mode; /* file protection mode */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,11 +61,259 @@ static const struct object_ops fd_ops =
|
|||||||
NULL, /* remove_queue */
|
NULL, /* remove_queue */
|
||||||
NULL, /* signaled */
|
NULL, /* signaled */
|
||||||
NULL, /* satisfied */
|
NULL, /* satisfied */
|
||||||
default_get_fd, /* get_fd */
|
no_get_fd, /* get_fd */
|
||||||
fd_destroy /* destroy */
|
fd_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* timeouts support */
|
||||||
|
|
||||||
|
struct timeout_user
|
||||||
|
{
|
||||||
|
struct timeout_user *next; /* next in sorted timeout list */
|
||||||
|
struct timeout_user *prev; /* prev in sorted timeout list */
|
||||||
|
struct timeval when; /* timeout expiry (absolute time) */
|
||||||
|
timeout_callback callback; /* callback function */
|
||||||
|
void *private; /* callback private data */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct timeout_user *timeout_head; /* sorted timeouts list head */
|
||||||
|
static struct timeout_user *timeout_tail; /* sorted timeouts list tail */
|
||||||
|
|
||||||
|
/* add a timeout user */
|
||||||
|
struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
|
||||||
|
{
|
||||||
|
struct timeout_user *user;
|
||||||
|
struct timeout_user *pos;
|
||||||
|
|
||||||
|
if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
|
||||||
|
user->when = *when;
|
||||||
|
user->callback = func;
|
||||||
|
user->private = private;
|
||||||
|
|
||||||
|
/* Now insert it in the linked list */
|
||||||
|
|
||||||
|
for (pos = timeout_head; pos; pos = pos->next)
|
||||||
|
if (!time_before( &pos->when, when )) break;
|
||||||
|
|
||||||
|
if (pos) /* insert it before 'pos' */
|
||||||
|
{
|
||||||
|
if ((user->prev = pos->prev)) user->prev->next = user;
|
||||||
|
else timeout_head = user;
|
||||||
|
user->next = pos;
|
||||||
|
pos->prev = user;
|
||||||
|
}
|
||||||
|
else /* insert it at the tail */
|
||||||
|
{
|
||||||
|
user->next = NULL;
|
||||||
|
if (timeout_tail) timeout_tail->next = user;
|
||||||
|
else timeout_head = user;
|
||||||
|
user->prev = timeout_tail;
|
||||||
|
timeout_tail = user;
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove a timeout user */
|
||||||
|
void remove_timeout_user( struct timeout_user *user )
|
||||||
|
{
|
||||||
|
if (user->next) user->next->prev = user->prev;
|
||||||
|
else timeout_tail = user->prev;
|
||||||
|
if (user->prev) user->prev->next = user->next;
|
||||||
|
else timeout_head = user->next;
|
||||||
|
free( user );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add a timeout in milliseconds to an absolute time */
|
||||||
|
void add_timeout( struct timeval *when, int timeout )
|
||||||
|
{
|
||||||
|
if (timeout)
|
||||||
|
{
|
||||||
|
long sec = timeout / 1000;
|
||||||
|
if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
|
||||||
|
{
|
||||||
|
when->tv_usec -= 1000000;
|
||||||
|
when->tv_sec++;
|
||||||
|
}
|
||||||
|
when->tv_sec += sec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle the next expired timeout */
|
||||||
|
inline static void handle_timeout(void)
|
||||||
|
{
|
||||||
|
struct timeout_user *user = timeout_head;
|
||||||
|
timeout_head = user->next;
|
||||||
|
if (user->next) user->next->prev = user->prev;
|
||||||
|
else timeout_tail = user->prev;
|
||||||
|
user->callback( user->private );
|
||||||
|
free( user );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* poll support */
|
||||||
|
|
||||||
|
static struct fd **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 fd **freelist; /* list of free entries in the array */
|
||||||
|
|
||||||
|
/* add a user in the poll array and return its index, or -1 on failure */
|
||||||
|
static int add_poll_user( struct fd *fd )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if (freelist)
|
||||||
|
{
|
||||||
|
ret = freelist - poll_users;
|
||||||
|
freelist = (struct fd **)poll_users[ret];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nb_users == allocated_users)
|
||||||
|
{
|
||||||
|
struct fd **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;
|
||||||
|
if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
|
||||||
|
{
|
||||||
|
if (allocated_users)
|
||||||
|
poll_users = newusers;
|
||||||
|
else
|
||||||
|
free( newusers );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
poll_users = newusers;
|
||||||
|
pollfd = newpoll;
|
||||||
|
allocated_users = new_count;
|
||||||
|
}
|
||||||
|
ret = nb_users++;
|
||||||
|
}
|
||||||
|
pollfd[ret].fd = -1;
|
||||||
|
pollfd[ret].events = 0;
|
||||||
|
pollfd[ret].revents = 0;
|
||||||
|
poll_users[ret] = fd;
|
||||||
|
active_users++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove a user from the poll list */
|
||||||
|
static void remove_poll_user( struct fd *fd, int user )
|
||||||
|
{
|
||||||
|
assert( user >= 0 );
|
||||||
|
assert( poll_users[user] == fd );
|
||||||
|
pollfd[user].fd = -1;
|
||||||
|
pollfd[user].events = 0;
|
||||||
|
pollfd[user].revents = 0;
|
||||||
|
poll_users[user] = (struct fd *)freelist;
|
||||||
|
freelist = &poll_users[user];
|
||||||
|
active_users--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SIGHUP handler */
|
||||||
|
static void sighup_handler()
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_OBJECTS
|
||||||
|
dump_objects();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SIGTERM handler */
|
||||||
|
static void sigterm_handler()
|
||||||
|
{
|
||||||
|
flush_registry();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SIGINT handler */
|
||||||
|
static void sigint_handler()
|
||||||
|
{
|
||||||
|
kill_all_processes( NULL, 1 );
|
||||||
|
flush_registry();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* server main poll() loop */
|
||||||
|
void main_loop(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
sigset_t sigset;
|
||||||
|
struct sigaction action;
|
||||||
|
|
||||||
|
/* block the signals we use */
|
||||||
|
sigemptyset( &sigset );
|
||||||
|
sigaddset( &sigset, SIGCHLD );
|
||||||
|
sigaddset( &sigset, SIGHUP );
|
||||||
|
sigaddset( &sigset, SIGINT );
|
||||||
|
sigaddset( &sigset, SIGQUIT );
|
||||||
|
sigaddset( &sigset, SIGTERM );
|
||||||
|
sigprocmask( SIG_BLOCK, &sigset, NULL );
|
||||||
|
|
||||||
|
/* set the handlers */
|
||||||
|
action.sa_mask = sigset;
|
||||||
|
action.sa_flags = 0;
|
||||||
|
action.sa_handler = sigchld_handler;
|
||||||
|
sigaction( SIGCHLD, &action, NULL );
|
||||||
|
action.sa_handler = sighup_handler;
|
||||||
|
sigaction( SIGHUP, &action, NULL );
|
||||||
|
action.sa_handler = sigint_handler;
|
||||||
|
sigaction( SIGINT, &action, NULL );
|
||||||
|
action.sa_handler = sigterm_handler;
|
||||||
|
sigaction( SIGQUIT, &action, NULL );
|
||||||
|
sigaction( SIGTERM, &action, NULL );
|
||||||
|
|
||||||
|
while (active_users)
|
||||||
|
{
|
||||||
|
long diff = -1;
|
||||||
|
if (timeout_head)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday( &now, NULL );
|
||||||
|
while (timeout_head)
|
||||||
|
{
|
||||||
|
if (!time_before( &now, &timeout_head->when )) handle_timeout();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
diff = (timeout_head->when.tv_sec - now.tv_sec) * 1000
|
||||||
|
+ (timeout_head->when.tv_usec - now.tv_usec) / 1000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!active_users) break; /* last user removed by a timeout */
|
||||||
|
}
|
||||||
|
|
||||||
|
sigprocmask( SIG_UNBLOCK, &sigset, NULL );
|
||||||
|
|
||||||
|
/* Note: we assume that the signal handlers do not manipulate the pollfd array
|
||||||
|
* or the timeout list, otherwise there is a race here.
|
||||||
|
*/
|
||||||
|
ret = poll( pollfd, nb_users, diff );
|
||||||
|
|
||||||
|
sigprocmask( SIG_BLOCK, &sigset, NULL );
|
||||||
|
|
||||||
|
if (ret > 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < nb_users; i++)
|
||||||
|
{
|
||||||
|
if (pollfd[i].revents)
|
||||||
|
{
|
||||||
|
fd_poll_event( poll_users[i], pollfd[i].revents );
|
||||||
|
if (!--ret) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* file descriptor functions */
|
||||||
|
|
||||||
static void fd_dump( struct object *obj, int verbose )
|
static void fd_dump( struct object *obj, int verbose )
|
||||||
{
|
{
|
||||||
struct fd *fd = (struct fd *)obj;
|
struct fd *fd = (struct fd *)obj;
|
||||||
@ -67,32 +322,53 @@ static void fd_dump( struct object *obj, int verbose )
|
|||||||
|
|
||||||
static void fd_destroy( struct object *obj )
|
static void fd_destroy( struct object *obj )
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
struct fd *fd = (struct fd *)obj;
|
struct fd *fd = (struct fd *)obj;
|
||||||
|
|
||||||
|
if (fd->poll_index != -1) remove_poll_user( fd, fd->poll_index );
|
||||||
close( fd->unix_fd );
|
close( fd->unix_fd );
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate an object that has an associated fd */
|
/* set the events that select waits for on this fd */
|
||||||
void *alloc_fd_object( const struct object_ops *ops,
|
void set_fd_events( struct fd *fd, int events )
|
||||||
const struct fd_ops *fd_user_ops, int unix_fd )
|
|
||||||
{
|
{
|
||||||
struct object *user;
|
int user = fd->poll_index;
|
||||||
struct fd *fd = alloc_object( &fd_ops, -1 );
|
assert( poll_users[user] == fd );
|
||||||
|
if (events == -1) /* stop waiting on this fd completely */
|
||||||
|
{
|
||||||
|
pollfd[user].fd = -1;
|
||||||
|
pollfd[user].events = POLLERR;
|
||||||
|
pollfd[user].revents = 0;
|
||||||
|
}
|
||||||
|
else if (pollfd[user].fd != -1 || !pollfd[user].events)
|
||||||
|
{
|
||||||
|
pollfd[user].fd = fd->unix_fd;
|
||||||
|
pollfd[user].events = events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!fd) return NULL;
|
/* allocate an fd object */
|
||||||
if (!(user = alloc_object( ops, unix_fd )))
|
/* if the function fails the unix fd is closed */
|
||||||
|
struct fd *alloc_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user )
|
||||||
|
{
|
||||||
|
struct fd *fd = alloc_object( &fd_ops );
|
||||||
|
|
||||||
|
if (!fd)
|
||||||
|
{
|
||||||
|
close( unix_fd );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fd->fd_ops = fd_user_ops;
|
||||||
|
fd->user = user;
|
||||||
|
fd->unix_fd = unix_fd;
|
||||||
|
fd->poll_index = -1;
|
||||||
|
fd->mode = 0;
|
||||||
|
|
||||||
|
if ((unix_fd != -1) && ((fd->poll_index = add_poll_user( fd )) == -1))
|
||||||
{
|
{
|
||||||
release_object( fd );
|
release_object( fd );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
fd->fd_ops = fd_user_ops;
|
return fd;
|
||||||
fd->user = user;
|
|
||||||
fd->unix_fd = unix_fd;
|
|
||||||
fd->mode = 0;
|
|
||||||
|
|
||||||
user->fd_obj = fd;
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* retrieve the object that is using an fd */
|
/* retrieve the object that is using an fd */
|
||||||
@ -104,26 +380,12 @@ void *get_fd_user( struct fd *fd )
|
|||||||
/* retrieve the unix fd for an object */
|
/* retrieve the unix fd for an object */
|
||||||
int get_unix_fd( struct fd *fd )
|
int get_unix_fd( struct fd *fd )
|
||||||
{
|
{
|
||||||
if (fd) return fd->unix_fd;
|
return fd->unix_fd;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the unix fd for an object; can only be done once */
|
|
||||||
void set_unix_fd( struct object *obj, int unix_fd )
|
|
||||||
{
|
|
||||||
struct fd *fd = obj->fd_obj;
|
|
||||||
|
|
||||||
assert( fd );
|
|
||||||
assert( fd->unix_fd == -1 );
|
|
||||||
|
|
||||||
fd->unix_fd = unix_fd;
|
|
||||||
obj->fd = unix_fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* callback for event happening in the main poll() loop */
|
/* callback for event happening in the main poll() loop */
|
||||||
void fd_poll_event( struct object *obj, int event )
|
void fd_poll_event( struct fd *fd, int event )
|
||||||
{
|
{
|
||||||
struct fd *fd = obj->fd_obj;
|
|
||||||
return fd->fd_ops->poll_event( fd, event );
|
return fd->fd_ops->poll_event( fd, event );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,46 +403,50 @@ int check_fd_events( struct fd *fd, int events )
|
|||||||
/* default add_queue() routine for objects that poll() on an fd */
|
/* default add_queue() routine for objects that poll() on an fd */
|
||||||
int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||||
{
|
{
|
||||||
struct fd *fd = obj->fd_obj;
|
struct fd *fd = get_obj_fd( obj );
|
||||||
|
|
||||||
|
if (!fd) return 0;
|
||||||
if (!obj->head) /* first on the queue */
|
if (!obj->head) /* first on the queue */
|
||||||
set_select_events( obj, fd->fd_ops->get_poll_events( fd ) );
|
set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) );
|
||||||
add_queue( obj, entry );
|
add_queue( obj, entry );
|
||||||
|
release_object( fd );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default remove_queue() routine for objects that poll() on an fd */
|
/* default remove_queue() routine for objects that poll() on an fd */
|
||||||
void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||||
{
|
{
|
||||||
|
struct fd *fd = get_obj_fd( obj );
|
||||||
|
|
||||||
grab_object( obj );
|
grab_object( obj );
|
||||||
remove_queue( obj, entry );
|
remove_queue( obj, entry );
|
||||||
if (!obj->head) /* last on the queue is gone */
|
if (!obj->head) /* last on the queue is gone */
|
||||||
set_select_events( obj, 0 );
|
set_fd_events( fd, 0 );
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
|
release_object( fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default signaled() routine for objects that poll() on an fd */
|
/* default signaled() routine for objects that poll() on an fd */
|
||||||
int default_fd_signaled( struct object *obj, struct thread *thread )
|
int default_fd_signaled( struct object *obj, struct thread *thread )
|
||||||
{
|
{
|
||||||
struct fd *fd = obj->fd_obj;
|
struct fd *fd = get_obj_fd( obj );
|
||||||
int events = fd->fd_ops->get_poll_events( fd );
|
int events = fd->fd_ops->get_poll_events( fd );
|
||||||
|
int ret = check_fd_events( fd, events ) != 0;
|
||||||
|
|
||||||
if (check_fd_events( fd, events ))
|
if (ret)
|
||||||
{
|
set_fd_events( fd, 0 ); /* stop waiting on select() if we are signaled */
|
||||||
/* stop waiting on select() if we are signaled */
|
else if (obj->head)
|
||||||
set_select_events( obj, 0 );
|
set_fd_events( fd, events ); /* restart waiting on poll() if we are no longer signaled */
|
||||||
return 1;
|
|
||||||
}
|
release_object( fd );
|
||||||
/* restart waiting on select() if we are no longer signaled */
|
return ret;
|
||||||
if (obj->head) set_select_events( obj, events );
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default handler for poll() events */
|
/* default handler for poll() events */
|
||||||
void default_poll_event( struct fd *fd, int event )
|
void default_poll_event( struct fd *fd, int event )
|
||||||
{
|
{
|
||||||
/* an error occurred, stop polling this fd to avoid busy-looping */
|
/* an error occurred, stop polling this fd to avoid busy-looping */
|
||||||
if (event & (POLLERR | POLLHUP)) set_select_events( fd->user, -1 );
|
if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
|
||||||
wake_up( fd->user, 0 );
|
wake_up( fd->user, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,8 +480,7 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
|
|||||||
|
|
||||||
if ((obj = get_handle_obj( process, handle, access, NULL )))
|
if ((obj = get_handle_obj( process, handle, access, NULL )))
|
||||||
{
|
{
|
||||||
if (obj->fd_obj) fd = (struct fd *)grab_object( obj->fd_obj );
|
if (!(fd = get_obj_fd( obj ))) set_error( STATUS_OBJECT_TYPE_MISMATCH );
|
||||||
else set_error( STATUS_OBJECT_TYPE_MISMATCH );
|
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
struct file
|
struct file
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
|
struct fd *fd; /* file descriptor for this file */
|
||||||
struct file *next; /* next file in hashing list */
|
struct file *next; /* next file in hashing list */
|
||||||
char *name; /* file name */
|
char *name; /* file name */
|
||||||
unsigned int access; /* file access (GENERIC_READ/WRITE) */
|
unsigned int access; /* file access (GENERIC_READ/WRITE) */
|
||||||
@ -66,6 +67,7 @@ struct file
|
|||||||
static struct file *file_hash[NAME_HASH_SIZE];
|
static struct file *file_hash[NAME_HASH_SIZE];
|
||||||
|
|
||||||
static void file_dump( struct object *obj, int verbose );
|
static void file_dump( struct object *obj, int verbose );
|
||||||
|
static struct fd *file_get_fd( struct object *obj );
|
||||||
static void file_destroy( struct object *obj );
|
static void file_destroy( struct object *obj );
|
||||||
|
|
||||||
static int file_get_poll_events( struct fd *fd );
|
static int file_get_poll_events( struct fd *fd );
|
||||||
@ -82,7 +84,7 @@ static const struct object_ops file_ops =
|
|||||||
default_fd_remove_queue, /* remove_queue */
|
default_fd_remove_queue, /* remove_queue */
|
||||||
default_fd_signaled, /* signaled */
|
default_fd_signaled, /* signaled */
|
||||||
no_satisfied, /* satisfied */
|
no_satisfied, /* satisfied */
|
||||||
default_get_fd, /* get_fd */
|
file_get_fd, /* get_fd */
|
||||||
file_destroy /* destroy */
|
file_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -134,7 +136,7 @@ static struct file *create_file_for_fd( int fd, unsigned int access, unsigned in
|
|||||||
{
|
{
|
||||||
struct file *file;
|
struct file *file;
|
||||||
|
|
||||||
if ((file = alloc_fd_object( &file_ops, &file_fd_ops, fd )))
|
if ((file = alloc_object( &file_ops )))
|
||||||
{
|
{
|
||||||
file->name = NULL;
|
file->name = NULL;
|
||||||
file->next = NULL;
|
file->next = NULL;
|
||||||
@ -147,6 +149,11 @@ static struct file *create_file_for_fd( int fd, unsigned int access, unsigned in
|
|||||||
init_async_queue (&file->read_q);
|
init_async_queue (&file->read_q);
|
||||||
init_async_queue (&file->write_q);
|
init_async_queue (&file->write_q);
|
||||||
}
|
}
|
||||||
|
if (!(file->fd = alloc_fd( &file_fd_ops, fd, &file->obj )))
|
||||||
|
{
|
||||||
|
release_object( file );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
@ -264,7 +271,7 @@ static void file_dump( struct object *obj, int verbose )
|
|||||||
{
|
{
|
||||||
struct file *file = (struct file *)obj;
|
struct file *file = (struct file *)obj;
|
||||||
assert( obj->ops == &file_ops );
|
assert( obj->ops == &file_ops );
|
||||||
fprintf( stderr, "File fd=%p flags=%08x name='%s'\n", file->obj.fd_obj, file->flags, file->name );
|
fprintf( stderr, "File fd=%p flags=%08x name='%s'\n", file->fd, file->flags, file->name );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int file_get_poll_events( struct fd *fd )
|
static int file_get_poll_events( struct fd *fd )
|
||||||
@ -395,7 +402,14 @@ static void file_queue_async(struct fd *fd, void *ptr, unsigned int status, int
|
|||||||
else if ( async ) destroy_async ( async );
|
else if ( async ) destroy_async ( async );
|
||||||
else set_error ( STATUS_INVALID_PARAMETER );
|
else set_error ( STATUS_INVALID_PARAMETER );
|
||||||
|
|
||||||
set_select_events( &file->obj, file_get_poll_events( fd ));
|
set_fd_events( fd, file_get_poll_events( fd ));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fd *file_get_fd( struct object *obj )
|
||||||
|
{
|
||||||
|
struct file *file = (struct file *)obj;
|
||||||
|
assert( obj->ops == &file_ops );
|
||||||
|
return (struct fd *)grab_object( file->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void file_destroy( struct object *obj )
|
static void file_destroy( struct object *obj )
|
||||||
@ -418,6 +432,7 @@ static void file_destroy( struct object *obj )
|
|||||||
destroy_async_queue (&file->read_q);
|
destroy_async_queue (&file->read_q);
|
||||||
destroy_async_queue (&file->write_q);
|
destroy_async_queue (&file->write_q);
|
||||||
}
|
}
|
||||||
|
if (file->fd) release_object( file->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the last error depending on errno */
|
/* set the last error depending on errno */
|
||||||
@ -453,7 +468,7 @@ struct file *get_file_obj( struct process *process, obj_handle_t handle, unsigne
|
|||||||
|
|
||||||
int get_file_unix_fd( struct file *file )
|
int get_file_unix_fd( struct file *file )
|
||||||
{
|
{
|
||||||
return get_unix_fd( file->obj.fd_obj );
|
return get_unix_fd( file->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_file_pointer( obj_handle_t handle, unsigned int *low, int *high, int whence )
|
static int set_file_pointer( obj_handle_t handle, unsigned int *low, int *high, int whence )
|
||||||
|
@ -42,13 +42,12 @@ struct fd_ops
|
|||||||
|
|
||||||
/* file descriptor functions */
|
/* file descriptor functions */
|
||||||
|
|
||||||
extern void *alloc_fd_object( const struct object_ops *ops,
|
extern struct fd *alloc_fd( const struct fd_ops *fd_ops, int unix_fd, struct object *user );
|
||||||
const struct fd_ops *fd_user_ops, int unix_fd );
|
|
||||||
extern void *get_fd_user( struct fd *fd );
|
extern void *get_fd_user( struct fd *fd );
|
||||||
extern int get_unix_fd( struct fd *fd );
|
extern int get_unix_fd( struct fd *fd );
|
||||||
extern void set_unix_fd( struct object *obj, int unix_fd );
|
extern void fd_poll_event( struct fd *fd, int event );
|
||||||
extern void fd_poll_event( struct object *obj, int event );
|
|
||||||
extern int check_fd_events( struct fd *fd, int events );
|
extern int check_fd_events( struct fd *fd, int events );
|
||||||
|
extern void set_fd_events( struct fd *fd, int events );
|
||||||
|
|
||||||
extern int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
extern int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
extern void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
extern void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
@ -57,9 +56,27 @@ extern void default_poll_event( struct fd *fd, int event );
|
|||||||
extern int no_flush( struct fd *fd );
|
extern int no_flush( struct fd *fd );
|
||||||
extern int no_get_file_info( struct fd *fd, struct get_file_info_reply *info, int *flags );
|
extern int no_get_file_info( struct fd *fd, struct get_file_info_reply *info, int *flags );
|
||||||
extern void no_queue_async( struct fd *fd, void* ptr, unsigned int status, int type, int count );
|
extern void no_queue_async( struct fd *fd, void* ptr, unsigned int status, int type, int count );
|
||||||
|
extern void main_loop(void);
|
||||||
|
|
||||||
inline static struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get_fd( obj ); }
|
inline static struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get_fd( obj ); }
|
||||||
|
|
||||||
|
/* timeout functions */
|
||||||
|
|
||||||
|
struct timeout_user;
|
||||||
|
|
||||||
|
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 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)));
|
||||||
|
}
|
||||||
|
|
||||||
/* file functions */
|
/* file functions */
|
||||||
|
|
||||||
extern struct file *get_file_obj( struct process *process, obj_handle_t handle,
|
extern struct file *get_file_obj( struct process *process, obj_handle_t handle,
|
||||||
|
@ -154,7 +154,7 @@ struct handle_table *alloc_handle_table( struct process *process, int count )
|
|||||||
struct handle_table *table;
|
struct handle_table *table;
|
||||||
|
|
||||||
if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
|
if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
|
||||||
if (!(table = alloc_object( &handle_table_ops, -1 )))
|
if (!(table = alloc_object( &handle_table_ops )))
|
||||||
return NULL;
|
return NULL;
|
||||||
table->process = process;
|
table->process = process;
|
||||||
table->count = count;
|
table->count = count;
|
||||||
|
@ -79,7 +79,7 @@ static struct hook_table *alloc_hook_table(void)
|
|||||||
struct hook_table *table;
|
struct hook_table *table;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if ((table = alloc_object( &hook_table_ops, -1 )))
|
if ((table = alloc_object( &hook_table_ops )))
|
||||||
{
|
{
|
||||||
for (i = 0; i < NB_HOOKS; i++)
|
for (i = 0; i < NB_HOOKS; i++)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "file.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ int main( int argc, char *argv[] )
|
|||||||
|
|
||||||
if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
|
if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
|
||||||
init_registry();
|
init_registry();
|
||||||
select_loop();
|
main_loop();
|
||||||
|
|
||||||
#ifdef DEBUG_OBJECTS
|
#ifdef DEBUG_OBJECTS
|
||||||
dump_objects(); /* dump any remaining objects */
|
dump_objects(); /* dump any remaining objects */
|
||||||
|
@ -50,6 +50,7 @@ struct mapping
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void mapping_dump( struct object *obj, int verbose );
|
static void mapping_dump( struct object *obj, int verbose );
|
||||||
|
static struct fd *mapping_get_fd( struct object *obj );
|
||||||
static void mapping_destroy( struct object *obj );
|
static void mapping_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops mapping_ops =
|
static const struct object_ops mapping_ops =
|
||||||
@ -60,7 +61,7 @@ static const struct object_ops mapping_ops =
|
|||||||
NULL, /* remove_queue */
|
NULL, /* remove_queue */
|
||||||
NULL, /* signaled */
|
NULL, /* signaled */
|
||||||
NULL, /* satisfied */
|
NULL, /* satisfied */
|
||||||
default_get_fd, /* get_fd */
|
mapping_get_fd, /* get_fd */
|
||||||
mapping_destroy /* destroy */
|
mapping_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -190,8 +191,7 @@ static int get_image_params( struct mapping *mapping )
|
|||||||
|
|
||||||
/* load the headers */
|
/* load the headers */
|
||||||
|
|
||||||
if (!(fd = get_obj_fd( (struct object *)mapping->file ))) return 0;
|
if (!(fd = mapping_get_fd( &mapping->obj ))) return 0;
|
||||||
mapping->obj.fd_obj = fd;
|
|
||||||
unix_fd = get_unix_fd( fd );
|
unix_fd = get_unix_fd( fd );
|
||||||
filepos = lseek( unix_fd, 0, SEEK_SET );
|
filepos = lseek( unix_fd, 0, SEEK_SET );
|
||||||
if (read( unix_fd, &dos, sizeof(dos) ) != sizeof(dos)) goto error;
|
if (read( unix_fd, &dos, sizeof(dos) ) != sizeof(dos)) goto error;
|
||||||
@ -231,11 +231,13 @@ static int get_image_params( struct mapping *mapping )
|
|||||||
|
|
||||||
lseek( unix_fd, filepos, SEEK_SET );
|
lseek( unix_fd, filepos, SEEK_SET );
|
||||||
free( sec );
|
free( sec );
|
||||||
|
release_object( fd );
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
lseek( unix_fd, filepos, SEEK_SET );
|
lseek( unix_fd, filepos, SEEK_SET );
|
||||||
if (sec) free( sec );
|
if (sec) free( sec );
|
||||||
|
release_object( fd );
|
||||||
set_error( STATUS_INVALID_FILE_FOR_SECTION );
|
set_error( STATUS_INVALID_FILE_FOR_SECTION );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -301,7 +303,6 @@ static struct object *create_mapping( int size_high, int size_low, int protect,
|
|||||||
if (!(mapping->file = create_temp_file( access ))) goto error;
|
if (!(mapping->file = create_temp_file( access ))) goto error;
|
||||||
if (!grow_file( mapping->file, size_high, size_low )) goto error;
|
if (!grow_file( mapping->file, size_high, size_low )) goto error;
|
||||||
}
|
}
|
||||||
mapping->obj.fd_obj = get_obj_fd( (struct object *)mapping->file );
|
|
||||||
mapping->size_high = size_high;
|
mapping->size_high = size_high;
|
||||||
mapping->size_low = ROUND_SIZE( 0, size_low );
|
mapping->size_low = ROUND_SIZE( 0, size_low );
|
||||||
mapping->protect = protect;
|
mapping->protect = protect;
|
||||||
@ -324,6 +325,12 @@ static void mapping_dump( struct object *obj, int verbose )
|
|||||||
fputc( '\n', stderr );
|
fputc( '\n', stderr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct fd *mapping_get_fd( struct object *obj )
|
||||||
|
{
|
||||||
|
struct mapping *mapping = (struct mapping *)obj;
|
||||||
|
return get_obj_fd( (struct object *)mapping->file );
|
||||||
|
}
|
||||||
|
|
||||||
static void mapping_destroy( struct object *obj )
|
static void mapping_destroy( struct object *obj )
|
||||||
{
|
{
|
||||||
struct mapping *mapping = (struct mapping *)obj;
|
struct mapping *mapping = (struct mapping *)obj;
|
||||||
|
@ -61,6 +61,7 @@ struct named_pipe;
|
|||||||
struct pipe_user
|
struct pipe_user
|
||||||
{
|
{
|
||||||
struct object obj;
|
struct object obj;
|
||||||
|
struct fd *fd;
|
||||||
enum pipe_state state;
|
enum pipe_state state;
|
||||||
struct pipe_user *other;
|
struct pipe_user *other;
|
||||||
struct named_pipe *pipe;
|
struct named_pipe *pipe;
|
||||||
@ -98,7 +99,10 @@ static const struct object_ops named_pipe_ops =
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void pipe_user_dump( struct object *obj, int verbose );
|
static void pipe_user_dump( struct object *obj, int verbose );
|
||||||
|
static struct fd *pipe_user_get_fd( struct object *obj );
|
||||||
static void pipe_user_destroy( struct object *obj);
|
static void pipe_user_destroy( struct object *obj);
|
||||||
|
|
||||||
|
static int pipe_user_get_poll_events( struct fd *fd );
|
||||||
static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags );
|
static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags );
|
||||||
|
|
||||||
static const struct object_ops pipe_user_ops =
|
static const struct object_ops pipe_user_ops =
|
||||||
@ -109,13 +113,13 @@ static const struct object_ops pipe_user_ops =
|
|||||||
default_fd_remove_queue, /* remove_queue */
|
default_fd_remove_queue, /* remove_queue */
|
||||||
default_fd_signaled, /* signaled */
|
default_fd_signaled, /* signaled */
|
||||||
no_satisfied, /* satisfied */
|
no_satisfied, /* satisfied */
|
||||||
default_get_fd, /* get_fd */
|
pipe_user_get_fd, /* get_fd */
|
||||||
pipe_user_destroy /* destroy */
|
pipe_user_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct fd_ops pipe_user_fd_ops =
|
static const struct fd_ops pipe_user_fd_ops =
|
||||||
{
|
{
|
||||||
NULL, /* get_poll_events */
|
pipe_user_get_poll_events, /* get_poll_events */
|
||||||
default_poll_event, /* poll_event */
|
default_poll_event, /* poll_event */
|
||||||
no_flush, /* flush */
|
no_flush, /* flush */
|
||||||
pipe_user_get_info, /* get_file_info */
|
pipe_user_get_info, /* get_file_info */
|
||||||
@ -156,6 +160,12 @@ static void notify_waiter( struct pipe_user *user, unsigned int status)
|
|||||||
user->overlapped=NULL;
|
user->overlapped=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct fd *pipe_user_get_fd( struct object *obj )
|
||||||
|
{
|
||||||
|
struct pipe_user *user = (struct pipe_user *)obj;
|
||||||
|
return (struct fd *)grab_object( user->fd );
|
||||||
|
}
|
||||||
|
|
||||||
static void pipe_user_destroy( struct object *obj)
|
static void pipe_user_destroy( struct object *obj)
|
||||||
{
|
{
|
||||||
struct pipe_user *user = (struct pipe_user *)obj;
|
struct pipe_user *user = (struct pipe_user *)obj;
|
||||||
@ -167,8 +177,8 @@ static void pipe_user_destroy( struct object *obj)
|
|||||||
|
|
||||||
if(user->other)
|
if(user->other)
|
||||||
{
|
{
|
||||||
release_object( user->other->obj.fd_obj );
|
release_object( user->other->fd );
|
||||||
user->other->obj.fd_obj = NULL;
|
user->other->fd = NULL;
|
||||||
switch(user->other->state)
|
switch(user->other->state)
|
||||||
{
|
{
|
||||||
case ps_connected_server:
|
case ps_connected_server:
|
||||||
@ -191,6 +201,12 @@ static void pipe_user_destroy( struct object *obj)
|
|||||||
else user->pipe->users = user->next;
|
else user->pipe->users = user->next;
|
||||||
if (user->thread) release_object(user->thread);
|
if (user->thread) release_object(user->thread);
|
||||||
release_object(user->pipe);
|
release_object(user->pipe);
|
||||||
|
if (user->fd) release_object( user->fd );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pipe_user_get_poll_events( struct fd *fd )
|
||||||
|
{
|
||||||
|
return POLLIN | POLLOUT; /* FIXME */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags )
|
static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags )
|
||||||
@ -227,20 +243,36 @@ static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
|
|||||||
return pipe;
|
return pipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct named_pipe *open_named_pipe( const WCHAR *name, size_t len )
|
||||||
|
{
|
||||||
|
struct object *obj;
|
||||||
|
|
||||||
|
if ((obj = find_object( sync_namespace, name, len )))
|
||||||
|
{
|
||||||
|
if (obj->ops == &named_pipe_ops) return (struct named_pipe *)obj;
|
||||||
|
release_object( obj );
|
||||||
|
set_error( STATUS_OBJECT_TYPE_MISMATCH );
|
||||||
|
}
|
||||||
|
else set_error( STATUS_OBJECT_NAME_NOT_FOUND );
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct pipe_user *get_pipe_user_obj( struct process *process, obj_handle_t handle,
|
static struct pipe_user *get_pipe_user_obj( struct process *process, obj_handle_t handle,
|
||||||
unsigned int access )
|
unsigned int access )
|
||||||
{
|
{
|
||||||
return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
|
return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
|
static struct pipe_user *create_pipe_user( struct named_pipe *pipe )
|
||||||
{
|
{
|
||||||
struct pipe_user *user;
|
struct pipe_user *user;
|
||||||
|
|
||||||
user = alloc_fd_object( &pipe_user_ops, &pipe_user_fd_ops, fd );
|
user = alloc_object( &pipe_user_ops );
|
||||||
if(!user)
|
if(!user)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
user->fd = NULL;
|
||||||
user->pipe = pipe;
|
user->pipe = pipe;
|
||||||
user->state = ps_none;
|
user->state = ps_none;
|
||||||
user->other = NULL;
|
user->other = NULL;
|
||||||
@ -293,7 +325,7 @@ DECL_HANDLER(create_named_pipe)
|
|||||||
pipe->pipemode = req->pipemode;
|
pipe->pipemode = req->pipemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
user = create_pipe_user (pipe, -1);
|
user = create_pipe_user( pipe );
|
||||||
|
|
||||||
if(user)
|
if(user)
|
||||||
{
|
{
|
||||||
@ -307,54 +339,46 @@ DECL_HANDLER(create_named_pipe)
|
|||||||
|
|
||||||
DECL_HANDLER(open_named_pipe)
|
DECL_HANDLER(open_named_pipe)
|
||||||
{
|
{
|
||||||
|
struct pipe_user *user, *partner;
|
||||||
struct named_pipe *pipe;
|
struct named_pipe *pipe;
|
||||||
|
|
||||||
reply->handle = 0;
|
reply->handle = 0;
|
||||||
pipe = create_named_pipe( get_req_data(), get_req_data_size() );
|
|
||||||
if(!pipe)
|
if (!(pipe = open_named_pipe( get_req_data(), get_req_data_size() )))
|
||||||
|
{
|
||||||
|
set_error( STATUS_NO_SUCH_FILE );
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (get_error() == STATUS_OBJECT_NAME_COLLISION)
|
if (!(partner = find_partner(pipe, ps_wait_open)))
|
||||||
{
|
{
|
||||||
struct pipe_user *partner;
|
release_object(pipe);
|
||||||
|
set_error( STATUS_PIPE_NOT_AVAILABLE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((user = create_pipe_user( pipe )))
|
||||||
|
{
|
||||||
|
int fds[2];
|
||||||
|
|
||||||
if ((partner = find_partner(pipe, ps_wait_open)))
|
if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
|
||||||
{
|
{
|
||||||
int fds[2];
|
user->fd = alloc_fd( &pipe_user_fd_ops, fds[1], &user->obj );
|
||||||
|
partner->fd = alloc_fd( &pipe_user_fd_ops, fds[0], &partner->obj );
|
||||||
if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
|
if (user->fd && partner->fd)
|
||||||
{
|
{
|
||||||
struct pipe_user *user;
|
notify_waiter(partner,STATUS_SUCCESS);
|
||||||
|
partner->state = ps_connected_server;
|
||||||
if( (user = create_pipe_user (pipe, fds[1])) )
|
partner->other = user;
|
||||||
{
|
user->state = ps_connected_client;
|
||||||
set_unix_fd( &partner->obj, fds[0] );
|
user->other = partner;
|
||||||
notify_waiter(partner,STATUS_SUCCESS);
|
reply->handle = alloc_handle( current->process, user, req->access, 0 );
|
||||||
partner->state = ps_connected_server;
|
|
||||||
partner->other = user;
|
|
||||||
user->state = ps_connected_client;
|
|
||||||
user->other = partner;
|
|
||||||
reply->handle = alloc_handle( current->process, user, req->access, 0 );
|
|
||||||
release_object(user);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
close(fds[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
release_object( partner );
|
|
||||||
}
|
}
|
||||||
else
|
else file_set_error();
|
||||||
{
|
|
||||||
set_error(STATUS_PIPE_NOT_AVAILABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
set_error(STATUS_NO_SUCH_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
release_object(pipe);
|
release_object( user );
|
||||||
|
}
|
||||||
|
release_object( partner );
|
||||||
|
release_object( pipe );
|
||||||
}
|
}
|
||||||
|
|
||||||
DECL_HANDLER(connect_named_pipe)
|
DECL_HANDLER(connect_named_pipe)
|
||||||
@ -381,7 +405,6 @@ DECL_HANDLER(connect_named_pipe)
|
|||||||
{
|
{
|
||||||
notify_waiter(partner,STATUS_SUCCESS);
|
notify_waiter(partner,STATUS_SUCCESS);
|
||||||
release_object(partner);
|
release_object(partner);
|
||||||
release_object(partner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,44 +414,35 @@ DECL_HANDLER(connect_named_pipe)
|
|||||||
DECL_HANDLER(wait_named_pipe)
|
DECL_HANDLER(wait_named_pipe)
|
||||||
{
|
{
|
||||||
struct named_pipe *pipe;
|
struct named_pipe *pipe;
|
||||||
|
struct pipe_user *partner;
|
||||||
|
|
||||||
pipe = create_named_pipe( get_req_data(), get_req_data_size() );
|
if (!(pipe = open_named_pipe( get_req_data(), get_req_data_size() )))
|
||||||
if( pipe )
|
|
||||||
{
|
{
|
||||||
/* only wait if the pipe already exists */
|
set_error( STATUS_PIPE_NOT_AVAILABLE );
|
||||||
if(get_error() == STATUS_OBJECT_NAME_COLLISION)
|
return;
|
||||||
{
|
|
||||||
struct pipe_user *partner;
|
|
||||||
|
|
||||||
set_error(STATUS_SUCCESS);
|
|
||||||
if( (partner = find_partner(pipe,ps_wait_open)) )
|
|
||||||
{
|
|
||||||
/* this should use notify_waiter,
|
|
||||||
but no pipe_user object exists now... */
|
|
||||||
thread_queue_apc(current,NULL,req->func,
|
|
||||||
APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS);
|
|
||||||
release_object(partner);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
struct pipe_user *user;
|
|
||||||
|
|
||||||
if( (user = create_pipe_user (pipe, -1)) )
|
|
||||||
{
|
|
||||||
user->state = ps_wait_connect;
|
|
||||||
user->thread = (struct thread *)grab_object(current);
|
|
||||||
user->func = req->func;
|
|
||||||
user->overlapped = req->overlapped;
|
|
||||||
/* don't release it */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
set_error(STATUS_PIPE_NOT_AVAILABLE);
|
|
||||||
}
|
|
||||||
release_object(pipe);
|
|
||||||
}
|
}
|
||||||
|
if( (partner = find_partner(pipe,ps_wait_open)) )
|
||||||
|
{
|
||||||
|
/* this should use notify_waiter,
|
||||||
|
but no pipe_user object exists now... */
|
||||||
|
thread_queue_apc(current,NULL,req->func,
|
||||||
|
APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS);
|
||||||
|
release_object(partner);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct pipe_user *user;
|
||||||
|
|
||||||
|
if( (user = create_pipe_user( pipe )) )
|
||||||
|
{
|
||||||
|
user->state = ps_wait_connect;
|
||||||
|
user->thread = (struct thread *)grab_object(current);
|
||||||
|
user->func = req->func;
|
||||||
|
user->overlapped = req->overlapped;
|
||||||
|
/* don't release it */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_object(pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
DECL_HANDLER(disconnect_named_pipe)
|
DECL_HANDLER(disconnect_named_pipe)
|
||||||
@ -441,13 +455,13 @@ DECL_HANDLER(disconnect_named_pipe)
|
|||||||
if( (user->state == ps_connected_server) &&
|
if( (user->state == ps_connected_server) &&
|
||||||
(user->other->state == ps_connected_client) )
|
(user->other->state == ps_connected_client) )
|
||||||
{
|
{
|
||||||
release_object( user->other->obj.fd_obj );
|
release_object( user->other->fd );
|
||||||
user->other->obj.fd_obj = NULL;
|
user->other->fd = NULL;
|
||||||
user->other->state = ps_disconnected;
|
user->other->state = ps_disconnected;
|
||||||
user->other->other = NULL;
|
user->other->other = NULL;
|
||||||
|
|
||||||
release_object( user->obj.fd_obj );
|
release_object( user->fd );
|
||||||
user->obj.fd_obj = NULL;
|
user->fd = NULL;
|
||||||
user->state = ps_idle_server;
|
user->state = ps_idle_server;
|
||||||
user->other = NULL;
|
user->other = NULL;
|
||||||
}
|
}
|
||||||
|
@ -131,32 +131,21 @@ static void set_object_name( struct namespace *namespace,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* allocate and initialize an object */
|
/* allocate and initialize an object */
|
||||||
/* if the function fails the fd is closed */
|
void *alloc_object( const struct object_ops *ops )
|
||||||
void *alloc_object( const struct object_ops *ops, int fd )
|
|
||||||
{
|
{
|
||||||
struct object *obj = mem_alloc( ops->size );
|
struct object *obj = mem_alloc( ops->size );
|
||||||
if (obj)
|
if (obj)
|
||||||
{
|
{
|
||||||
obj->refcount = 1;
|
obj->refcount = 1;
|
||||||
obj->fd_obj = NULL;
|
|
||||||
obj->fd = fd;
|
|
||||||
obj->select = -1;
|
|
||||||
obj->ops = ops;
|
obj->ops = ops;
|
||||||
obj->head = NULL;
|
obj->head = NULL;
|
||||||
obj->tail = NULL;
|
obj->tail = NULL;
|
||||||
obj->name = NULL;
|
obj->name = NULL;
|
||||||
if ((fd != -1) && (add_select_user( obj ) == -1))
|
|
||||||
{
|
|
||||||
close( fd );
|
|
||||||
free( obj );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_OBJECTS
|
#ifdef DEBUG_OBJECTS
|
||||||
list_add_head( &object_list, &obj->obj_list );
|
list_add_head( &object_list, &obj->obj_list );
|
||||||
#endif
|
#endif
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
if (fd != -1) close( fd );
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +155,7 @@ void *create_named_object( struct namespace *namespace, const struct object_ops
|
|||||||
struct object *obj;
|
struct object *obj;
|
||||||
struct object_name *name_ptr;
|
struct object_name *name_ptr;
|
||||||
|
|
||||||
if (!name || !len) return alloc_object( ops, -1 );
|
if (!name || !len) return alloc_object( ops );
|
||||||
|
|
||||||
if ((obj = find_object( namespace, name, len )))
|
if ((obj = find_object( namespace, name, len )))
|
||||||
{
|
{
|
||||||
@ -179,7 +168,7 @@ void *create_named_object( struct namespace *namespace, const struct object_ops
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(name_ptr = alloc_name( name, len ))) return NULL;
|
if (!(name_ptr = alloc_name( name, len ))) return NULL;
|
||||||
if ((obj = alloc_object( ops, -1 )))
|
if ((obj = alloc_object( ops )))
|
||||||
{
|
{
|
||||||
set_object_name( namespace, obj, name_ptr );
|
set_object_name( namespace, obj, name_ptr );
|
||||||
clear_error();
|
clear_error();
|
||||||
@ -220,10 +209,7 @@ void release_object( void *ptr )
|
|||||||
assert( !obj->head );
|
assert( !obj->head );
|
||||||
assert( !obj->tail );
|
assert( !obj->tail );
|
||||||
obj->ops->destroy( obj );
|
obj->ops->destroy( obj );
|
||||||
if (obj->fd_obj) release_object( obj->fd_obj );
|
|
||||||
if (obj->name) free_name( 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
|
#ifdef DEBUG_OBJECTS
|
||||||
list_remove( &obj->obj_list );
|
list_remove( &obj->obj_list );
|
||||||
memset( obj, 0xaa, obj->ops->size );
|
memset( obj, 0xaa, obj->ops->size );
|
||||||
@ -296,13 +282,6 @@ struct fd *no_get_fd( struct object *obj )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fd *default_get_fd( struct object *obj )
|
|
||||||
{
|
|
||||||
if (obj->fd_obj) return (struct fd *)grab_object( obj->fd_obj );
|
|
||||||
set_error( STATUS_OBJECT_TYPE_MISMATCH );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void no_destroy( struct object *obj )
|
void no_destroy( struct object *obj )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -67,9 +67,6 @@ struct object_ops
|
|||||||
struct object
|
struct object
|
||||||
{
|
{
|
||||||
unsigned int refcount; /* reference count */
|
unsigned int refcount; /* reference count */
|
||||||
struct fd *fd_obj; /* file descriptor */
|
|
||||||
int fd; /* file descriptor */
|
|
||||||
int select; /* select() user id */
|
|
||||||
const struct object_ops *ops;
|
const struct object_ops *ops;
|
||||||
struct wait_queue_entry *head;
|
struct wait_queue_entry *head;
|
||||||
struct wait_queue_entry *tail;
|
struct wait_queue_entry *tail;
|
||||||
@ -89,7 +86,7 @@ struct wait_queue_entry
|
|||||||
|
|
||||||
extern void *mem_alloc( size_t size ); /* malloc wrapper */
|
extern void *mem_alloc( size_t size ); /* malloc wrapper */
|
||||||
extern void *memdup( const void *data, size_t len );
|
extern void *memdup( const void *data, size_t len );
|
||||||
extern void *alloc_object( const struct object_ops *ops, int fd );
|
extern void *alloc_object( const struct object_ops *ops );
|
||||||
extern void dump_object_name( struct object *obj );
|
extern void dump_object_name( struct object *obj );
|
||||||
extern void *create_named_object( struct namespace *namespace, const struct object_ops *ops,
|
extern void *create_named_object( struct namespace *namespace, const struct object_ops *ops,
|
||||||
const WCHAR *name, size_t len );
|
const WCHAR *name, size_t len );
|
||||||
@ -102,37 +99,11 @@ extern struct object *find_object( const struct namespace *namespace, const WCHA
|
|||||||
extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
extern int no_satisfied( struct object *obj, struct thread *thread );
|
extern int no_satisfied( struct object *obj, struct thread *thread );
|
||||||
extern struct fd *no_get_fd( struct object *obj );
|
extern struct fd *no_get_fd( struct object *obj );
|
||||||
extern struct fd *default_get_fd( struct object *obj );
|
|
||||||
extern void no_destroy( struct object *obj );
|
extern void no_destroy( struct object *obj );
|
||||||
#ifdef DEBUG_OBJECTS
|
#ifdef DEBUG_OBJECTS
|
||||||
extern void dump_objects(void);
|
extern void dump_objects(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* select functions */
|
|
||||||
|
|
||||||
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, int events );
|
|
||||||
extern void set_select_events( struct object *obj, int events );
|
|
||||||
extern void select_loop(void);
|
|
||||||
|
|
||||||
/* timeout functions */
|
|
||||||
|
|
||||||
struct timeout_user;
|
|
||||||
|
|
||||||
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 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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* event functions */
|
/* event functions */
|
||||||
|
|
||||||
struct event;
|
struct event;
|
||||||
|
@ -42,6 +42,7 @@ enum side { READ_SIDE, WRITE_SIDE };
|
|||||||
struct pipe
|
struct pipe
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
|
struct fd *fd; /* pipe file descriptor */
|
||||||
struct pipe *other; /* the pipe other end */
|
struct pipe *other; /* the pipe other end */
|
||||||
enum side side; /* which side of the pipe is this */
|
enum side side; /* which side of the pipe is this */
|
||||||
};
|
};
|
||||||
@ -79,11 +80,16 @@ static struct pipe *create_pipe_side( int fd, int side )
|
|||||||
{
|
{
|
||||||
struct pipe *pipe;
|
struct pipe *pipe;
|
||||||
|
|
||||||
if ((pipe = alloc_fd_object( &pipe_ops, &pipe_fd_ops, fd )))
|
if ((pipe = alloc_object( &pipe_ops )))
|
||||||
{
|
{
|
||||||
pipe->other = NULL;
|
pipe->other = NULL;
|
||||||
pipe->side = side;
|
pipe->side = side;
|
||||||
}
|
}
|
||||||
|
if (!(pipe->fd = alloc_fd( &pipe_fd_ops, fd, &pipe->obj )))
|
||||||
|
{
|
||||||
|
release_object( pipe );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return pipe;
|
return pipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +125,7 @@ static void pipe_dump( struct object *obj, int verbose )
|
|||||||
struct pipe *pipe = (struct pipe *)obj;
|
struct pipe *pipe = (struct pipe *)obj;
|
||||||
assert( obj->ops == &pipe_ops );
|
assert( obj->ops == &pipe_ops );
|
||||||
fprintf( stderr, "Pipe %s-side fd=%p\n",
|
fprintf( stderr, "Pipe %s-side fd=%p\n",
|
||||||
(pipe->side == READ_SIDE) ? "read" : "write", pipe->obj.fd_obj );
|
(pipe->side == READ_SIDE) ? "read" : "write", pipe->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pipe_get_poll_events( struct fd *fd )
|
static int pipe_get_poll_events( struct fd *fd )
|
||||||
@ -139,7 +145,7 @@ static struct fd *pipe_get_fd( struct object *obj )
|
|||||||
set_error( STATUS_PIPE_BROKEN );
|
set_error( STATUS_PIPE_BROKEN );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return (struct fd *)grab_object( pipe->obj.fd_obj );
|
return (struct fd *)grab_object( pipe->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pipe_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags )
|
static int pipe_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags )
|
||||||
@ -167,6 +173,7 @@ static void pipe_destroy( struct object *obj )
|
|||||||
assert( obj->ops == &pipe_ops );
|
assert( obj->ops == &pipe_ops );
|
||||||
|
|
||||||
if (pipe->other) pipe->other->other = NULL;
|
if (pipe->other) pipe->other->other = NULL;
|
||||||
|
if (pipe->fd) release_object( pipe->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create an anonymous pipe */
|
/* create an anonymous pipe */
|
||||||
|
@ -263,13 +263,14 @@ struct thread *create_process( int fd )
|
|||||||
struct thread *thread = NULL;
|
struct thread *thread = NULL;
|
||||||
int request_pipe[2];
|
int request_pipe[2];
|
||||||
|
|
||||||
if (!(process = alloc_fd_object( &process_ops, &process_fd_ops, fd ))) goto error;
|
if (!(process = alloc_object( &process_ops ))) goto error;
|
||||||
process->next = NULL;
|
process->next = NULL;
|
||||||
process->prev = NULL;
|
process->prev = NULL;
|
||||||
process->parent = NULL;
|
process->parent = NULL;
|
||||||
process->thread_list = NULL;
|
process->thread_list = NULL;
|
||||||
process->debugger = NULL;
|
process->debugger = NULL;
|
||||||
process->handles = NULL;
|
process->handles = NULL;
|
||||||
|
process->msg_fd = NULL;
|
||||||
process->exit_code = STILL_ACTIVE;
|
process->exit_code = STILL_ACTIVE;
|
||||||
process->running_threads = 0;
|
process->running_threads = 0;
|
||||||
process->priority = NORMAL_PRIORITY_CLASS;
|
process->priority = NORMAL_PRIORITY_CLASS;
|
||||||
@ -297,6 +298,7 @@ struct thread *create_process( int fd )
|
|||||||
first_process = process;
|
first_process = process;
|
||||||
|
|
||||||
if (!(process->id = alloc_ptid( process ))) goto error;
|
if (!(process->id = alloc_ptid( process ))) goto error;
|
||||||
|
if (!(process->msg_fd = alloc_fd( &process_fd_ops, fd, &process->obj ))) goto error;
|
||||||
|
|
||||||
/* create the main thread */
|
/* create the main thread */
|
||||||
if (pipe( request_pipe ) == -1)
|
if (pipe( request_pipe ) == -1)
|
||||||
@ -313,7 +315,7 @@ struct thread *create_process( int fd )
|
|||||||
close( request_pipe[1] );
|
close( request_pipe[1] );
|
||||||
if (!(thread = create_thread( request_pipe[0], process ))) goto error;
|
if (!(thread = create_thread( request_pipe[0], process ))) goto error;
|
||||||
|
|
||||||
set_select_events( &process->obj, POLLIN ); /* start listening to events */
|
set_fd_events( process->msg_fd, POLLIN ); /* start listening to events */
|
||||||
release_object( process );
|
release_object( process );
|
||||||
return thread;
|
return thread;
|
||||||
|
|
||||||
@ -404,6 +406,7 @@ static void process_destroy( struct object *obj )
|
|||||||
set_process_startup_state( process, STARTUP_ABORTED );
|
set_process_startup_state( process, STARTUP_ABORTED );
|
||||||
if (process->console) release_object( process->console );
|
if (process->console) release_object( process->console );
|
||||||
if (process->parent) release_object( process->parent );
|
if (process->parent) release_object( process->parent );
|
||||||
|
if (process->msg_fd) release_object( process->msg_fd );
|
||||||
if (process->next) process->next->prev = process->prev;
|
if (process->next) process->next->prev = process->prev;
|
||||||
if (process->prev) process->prev->next = process->next;
|
if (process->prev) process->prev->next = process->next;
|
||||||
else first_process = process->next;
|
else first_process = process->next;
|
||||||
@ -431,13 +434,12 @@ static int process_signaled( struct object *obj, struct thread *thread )
|
|||||||
return !process->running_threads;
|
return !process->running_threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void process_poll_event( struct fd *fd, int event )
|
static void process_poll_event( struct fd *fd, int event )
|
||||||
{
|
{
|
||||||
struct process *process = get_fd_user( fd );
|
struct process *process = get_fd_user( fd );
|
||||||
assert( process->obj.ops == &process_ops );
|
assert( process->obj.ops == &process_ops );
|
||||||
|
|
||||||
if (event & (POLLERR | POLLHUP)) set_select_events( &process->obj, -1 );
|
if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
|
||||||
else if (event & POLLIN) receive_fd( process );
|
else if (event & POLLIN) receive_fd( process );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -883,7 +885,7 @@ DECL_HANDLER(new_process)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* build the startup info for a new process */
|
/* build the startup info for a new process */
|
||||||
if (!(info = alloc_object( &startup_info_ops, -1 ))) return;
|
if (!(info = alloc_object( &startup_info_ops ))) return;
|
||||||
info->inherit_all = req->inherit_all;
|
info->inherit_all = req->inherit_all;
|
||||||
info->use_handles = req->use_handles;
|
info->use_handles = req->use_handles;
|
||||||
info->create_flags = req->create_flags;
|
info->create_flags = req->create_flags;
|
||||||
|
@ -56,6 +56,7 @@ struct process
|
|||||||
struct thread *thread_list; /* head of the thread list */
|
struct thread *thread_list; /* head of the thread list */
|
||||||
struct thread *debugger; /* thread debugging this process */
|
struct thread *debugger; /* thread debugging this process */
|
||||||
struct handle_table *handles; /* handle entries */
|
struct handle_table *handles; /* handle entries */
|
||||||
|
struct fd *msg_fd; /* fd for sendmsg/recvmsg */
|
||||||
process_id_t id; /* id of the process */
|
process_id_t id; /* id of the process */
|
||||||
process_id_t group_id; /* group id of the process */
|
process_id_t group_id; /* group id of the process */
|
||||||
int exit_code; /* process exit code */
|
int exit_code; /* process exit code */
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "winuser.h"
|
#include "winuser.h"
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
|
#include "file.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
@ -181,7 +182,7 @@ static struct thread_input *create_thread_input(void)
|
|||||||
{
|
{
|
||||||
struct thread_input *input;
|
struct thread_input *input;
|
||||||
|
|
||||||
if ((input = alloc_object( &thread_input_ops, -1 )))
|
if ((input = alloc_object( &thread_input_ops )))
|
||||||
{
|
{
|
||||||
input->focus = 0;
|
input->focus = 0;
|
||||||
input->capture = 0;
|
input->capture = 0;
|
||||||
@ -204,7 +205,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!input && !(input = create_thread_input())) return NULL;
|
if (!input && !(input = create_thread_input())) return NULL;
|
||||||
if ((queue = alloc_object( &msg_queue_ops, -1 )))
|
if ((queue = alloc_object( &msg_queue_ops )))
|
||||||
{
|
{
|
||||||
queue->wake_bits = 0;
|
queue->wake_bits = 0;
|
||||||
queue->wake_mask = 0;
|
queue->wake_mask = 0;
|
||||||
|
@ -434,7 +434,7 @@ static WCHAR *req_strdupW( const void *req, const WCHAR *str, size_t len )
|
|||||||
static struct key *alloc_key( const WCHAR *name, time_t modif )
|
static struct key *alloc_key( const WCHAR *name, time_t modif )
|
||||||
{
|
{
|
||||||
struct key *key;
|
struct key *key;
|
||||||
if ((key = (struct key *)alloc_object( &key_ops, -1 )))
|
if ((key = alloc_object( &key_ops )))
|
||||||
{
|
{
|
||||||
key->class = NULL;
|
key->class = NULL;
|
||||||
key->flags = 0;
|
key->flags = 0;
|
||||||
|
@ -73,11 +73,13 @@ static const char * const server_lock_name = "lock"; /* name of the server
|
|||||||
|
|
||||||
struct master_socket
|
struct master_socket
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
|
struct fd *fd; /* file descriptor of the master socket */
|
||||||
struct timeout_user *timeout; /* timeout on last process exit */
|
struct timeout_user *timeout; /* timeout on last process exit */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void master_socket_dump( struct object *obj, int verbose );
|
static void master_socket_dump( struct object *obj, int verbose );
|
||||||
|
static void master_socket_destroy( struct object *obj );
|
||||||
static void master_socket_poll_event( struct fd *fd, int event );
|
static void master_socket_poll_event( struct fd *fd, int event );
|
||||||
|
|
||||||
static const struct object_ops master_socket_ops =
|
static const struct object_ops master_socket_ops =
|
||||||
@ -89,7 +91,7 @@ static const struct object_ops master_socket_ops =
|
|||||||
NULL, /* signaled */
|
NULL, /* signaled */
|
||||||
NULL, /* satisfied */
|
NULL, /* satisfied */
|
||||||
no_get_fd, /* get_fd */
|
no_get_fd, /* get_fd */
|
||||||
no_destroy /* destroy */
|
master_socket_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct fd_ops master_socket_fd_ops =
|
static const struct fd_ops master_socket_fd_ops =
|
||||||
@ -188,7 +190,7 @@ void write_reply( struct thread *thread )
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = write( thread->reply_fd,
|
if ((ret = write( get_unix_fd( thread->reply_fd ),
|
||||||
(char *)thread->reply_data + thread->reply_size - thread->reply_towrite,
|
(char *)thread->reply_data + thread->reply_size - thread->reply_towrite,
|
||||||
thread->reply_towrite )) >= 0)
|
thread->reply_towrite )) >= 0)
|
||||||
{
|
{
|
||||||
@ -197,7 +199,8 @@ void write_reply( struct thread *thread )
|
|||||||
free( thread->reply_data );
|
free( thread->reply_data );
|
||||||
thread->reply_data = NULL;
|
thread->reply_data = NULL;
|
||||||
/* sent everything, can go back to waiting for requests */
|
/* sent everything, can go back to waiting for requests */
|
||||||
change_select_fd( &thread->obj, thread->request_fd, POLLIN );
|
set_fd_events( thread->request_fd, POLLIN );
|
||||||
|
set_fd_events( thread->reply_fd, 0 );
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -214,7 +217,8 @@ static void send_reply( union generic_reply *reply )
|
|||||||
|
|
||||||
if (!current->reply_size)
|
if (!current->reply_size)
|
||||||
{
|
{
|
||||||
if ((ret = write( current->reply_fd, reply, sizeof(*reply) )) != sizeof(*reply)) goto error;
|
if ((ret = write( get_unix_fd( current->reply_fd ),
|
||||||
|
reply, sizeof(*reply) )) != sizeof(*reply)) goto error;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -225,12 +229,13 @@ static void send_reply( union generic_reply *reply )
|
|||||||
vec[1].iov_base = current->reply_data;
|
vec[1].iov_base = current->reply_data;
|
||||||
vec[1].iov_len = current->reply_size;
|
vec[1].iov_len = current->reply_size;
|
||||||
|
|
||||||
if ((ret = writev( current->reply_fd, vec, 2 )) < sizeof(*reply)) goto error;
|
if ((ret = writev( get_unix_fd( current->reply_fd ), vec, 2 )) < sizeof(*reply)) goto error;
|
||||||
|
|
||||||
if ((current->reply_towrite = current->reply_size - (ret - sizeof(*reply))))
|
if ((current->reply_towrite = current->reply_size - (ret - sizeof(*reply))))
|
||||||
{
|
{
|
||||||
/* couldn't write it all, wait for POLLOUT */
|
/* couldn't write it all, wait for POLLOUT */
|
||||||
change_select_fd( ¤t->obj, current->reply_fd, POLLOUT );
|
set_fd_events( current->reply_fd, POLLOUT );
|
||||||
|
set_fd_events( current->request_fd, 0 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,7 +291,7 @@ void read_request( struct thread *thread )
|
|||||||
|
|
||||||
if (!thread->req_toread) /* no pending request */
|
if (!thread->req_toread) /* no pending request */
|
||||||
{
|
{
|
||||||
if ((ret = read( thread->obj.fd, &thread->req,
|
if ((ret = read( get_unix_fd( thread->request_fd ), &thread->req,
|
||||||
sizeof(thread->req) )) != sizeof(thread->req)) goto error;
|
sizeof(thread->req) )) != sizeof(thread->req)) goto error;
|
||||||
if (!(thread->req_toread = thread->req.request_header.request_size))
|
if (!(thread->req_toread = thread->req.request_header.request_size))
|
||||||
{
|
{
|
||||||
@ -301,8 +306,9 @@ void read_request( struct thread *thread )
|
|||||||
/* read the variable sized data */
|
/* read the variable sized data */
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
ret = read( thread->obj.fd, ((char *)thread->req_data +
|
ret = read( get_unix_fd( thread->request_fd ),
|
||||||
thread->req.request_header.request_size - thread->req_toread),
|
(char *)thread->req_data + thread->req.request_header.request_size
|
||||||
|
- thread->req_toread,
|
||||||
thread->req_toread );
|
thread->req_toread );
|
||||||
if (ret <= 0) break;
|
if (ret <= 0) break;
|
||||||
if (!(thread->req_toread -= ret))
|
if (!(thread->req_toread -= ret))
|
||||||
@ -341,7 +347,7 @@ int receive_fd( struct process *process )
|
|||||||
myiovec.iov_base = (void *)&data;
|
myiovec.iov_base = (void *)&data;
|
||||||
myiovec.iov_len = sizeof(data);
|
myiovec.iov_len = sizeof(data);
|
||||||
|
|
||||||
ret = recvmsg( process->obj.fd, &msghdr, 0 );
|
ret = recvmsg( get_unix_fd( process->msg_fd ), &msghdr, 0 );
|
||||||
#ifndef HAVE_MSGHDR_ACCRIGHTS
|
#ifndef HAVE_MSGHDR_ACCRIGHTS
|
||||||
fd = cmsg.fd;
|
fd = cmsg.fd;
|
||||||
#endif
|
#endif
|
||||||
@ -411,7 +417,7 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle )
|
|||||||
myiovec.iov_base = (void *)&handle;
|
myiovec.iov_base = (void *)&handle;
|
||||||
myiovec.iov_len = sizeof(handle);
|
myiovec.iov_len = sizeof(handle);
|
||||||
|
|
||||||
ret = sendmsg( process->obj.fd, &msghdr, 0 );
|
ret = sendmsg( get_unix_fd( process->msg_fd ), &msghdr, 0 );
|
||||||
|
|
||||||
if (ret == sizeof(handle)) return 0;
|
if (ret == sizeof(handle)) return 0;
|
||||||
|
|
||||||
@ -445,7 +451,14 @@ static void master_socket_dump( struct object *obj, int verbose )
|
|||||||
{
|
{
|
||||||
struct master_socket *sock = (struct master_socket *)obj;
|
struct master_socket *sock = (struct master_socket *)obj;
|
||||||
assert( obj->ops == &master_socket_ops );
|
assert( obj->ops == &master_socket_ops );
|
||||||
fprintf( stderr, "Master socket fd=%p\n", sock->obj.fd_obj );
|
fprintf( stderr, "Master socket fd=%p\n", sock->fd );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void master_socket_destroy( struct object *obj )
|
||||||
|
{
|
||||||
|
struct master_socket *sock = (struct master_socket *)obj;
|
||||||
|
assert( obj->ops == &master_socket_ops );
|
||||||
|
release_object( sock->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle a socket event */
|
/* handle a socket event */
|
||||||
@ -466,7 +479,7 @@ static void master_socket_poll_event( struct fd *fd, int event )
|
|||||||
{
|
{
|
||||||
struct sockaddr_un dummy;
|
struct sockaddr_un dummy;
|
||||||
int len = sizeof(dummy);
|
int len = sizeof(dummy);
|
||||||
int client = accept( master_socket->obj.fd, (struct sockaddr *) &dummy, &len );
|
int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len );
|
||||||
if (client == -1) return;
|
if (client == -1) return;
|
||||||
if (sock->timeout)
|
if (sock->timeout)
|
||||||
{
|
{
|
||||||
@ -682,10 +695,11 @@ static void acquire_lock(void)
|
|||||||
chmod( server_socket_name, 0600 ); /* make sure no other user can connect */
|
chmod( server_socket_name, 0600 ); /* make sure no other user can connect */
|
||||||
if (listen( fd, 5 ) == -1) fatal_perror( "listen" );
|
if (listen( fd, 5 ) == -1) fatal_perror( "listen" );
|
||||||
|
|
||||||
if (!(master_socket = alloc_fd_object( &master_socket_ops, &master_socket_fd_ops, fd )))
|
if (!(master_socket = alloc_object( &master_socket_ops )) ||
|
||||||
|
!(master_socket->fd = alloc_fd( &master_socket_fd_ops, fd, &master_socket->obj )))
|
||||||
fatal_error( "out of memory\n" );
|
fatal_error( "out of memory\n" );
|
||||||
master_socket->timeout = NULL;
|
master_socket->timeout = NULL;
|
||||||
set_select_events( &master_socket->obj, POLLIN );
|
set_fd_events( master_socket->fd, POLLIN );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open the master server socket and start waiting for new clients */
|
/* open the master server socket and start waiting for new clients */
|
||||||
@ -748,7 +762,7 @@ static void close_socket_timeout( void *arg )
|
|||||||
flush_registry();
|
flush_registry();
|
||||||
|
|
||||||
/* if a new client is waiting, we keep on running */
|
/* if a new client is waiting, we keep on running */
|
||||||
if (check_fd_events( master_socket->obj.fd_obj, POLLIN )) return;
|
if (check_fd_events( master_socket->fd, POLLIN )) return;
|
||||||
|
|
||||||
if (debug_level) fprintf( stderr, "wineserver: exiting (pid=%ld)\n", (long) getpid() );
|
if (debug_level) fprintf( stderr, "wineserver: exiting (pid=%ld)\n", (long) getpid() );
|
||||||
|
|
||||||
@ -783,5 +797,5 @@ void close_master_socket(void)
|
|||||||
/* lock/unlock the master socket to stop accepting new clients */
|
/* lock/unlock the master socket to stop accepting new clients */
|
||||||
void lock_master_socket( int locked )
|
void lock_master_socket( int locked )
|
||||||
{
|
{
|
||||||
set_select_events( &master_socket->obj, locked ? 0 : POLLIN );
|
set_fd_events( master_socket->fd, locked ? 0 : POLLIN );
|
||||||
}
|
}
|
||||||
|
305
server/select.c
305
server/select.c
@ -1,305 +0,0 @@
|
|||||||
/*
|
|
||||||
* Server main select() loop
|
|
||||||
*
|
|
||||||
* Copyright (C) 1998 Alexandre Julliard
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#ifdef HAVE_SYS_POLL_H
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "file.h"
|
|
||||||
#include "thread.h"
|
|
||||||
#include "process.h"
|
|
||||||
|
|
||||||
struct timeout_user
|
|
||||||
{
|
|
||||||
struct timeout_user *next; /* next in sorted timeout list */
|
|
||||||
struct timeout_user *prev; /* prev in sorted timeout list */
|
|
||||||
struct timeval when; /* timeout expiry (absolute time) */
|
|
||||||
timeout_callback callback; /* callback function */
|
|
||||||
void *private; /* callback private data */
|
|
||||||
};
|
|
||||||
|
|
||||||
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 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( struct object *obj )
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
if (freelist)
|
|
||||||
{
|
|
||||||
ret = freelist - poll_users;
|
|
||||||
freelist = (struct object **)poll_users[ret];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (nb_users == allocated_users)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
|
|
||||||
{
|
|
||||||
if (allocated_users)
|
|
||||||
poll_users = newusers;
|
|
||||||
else
|
|
||||||
free( newusers );
|
|
||||||
obj->select = -1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
poll_users = newusers;
|
|
||||||
pollfd = newpoll;
|
|
||||||
allocated_users = new_count;
|
|
||||||
}
|
|
||||||
ret = nb_users++;
|
|
||||||
}
|
|
||||||
pollfd[ret].fd = obj->fd;
|
|
||||||
pollfd[ret].events = 0;
|
|
||||||
pollfd[ret].revents = 0;
|
|
||||||
poll_users[ret] = obj;
|
|
||||||
obj->select = ret;
|
|
||||||
active_users++;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove an object from the select list and close its fd */
|
|
||||||
void remove_select_user( struct object *obj )
|
|
||||||
{
|
|
||||||
int user = obj->select;
|
|
||||||
assert( user >= 0 );
|
|
||||||
assert( poll_users[user] == obj );
|
|
||||||
pollfd[user].fd = -1;
|
|
||||||
pollfd[user].events = 0;
|
|
||||||
pollfd[user].revents = 0;
|
|
||||||
poll_users[user] = (struct object *)freelist;
|
|
||||||
freelist = &poll_users[user];
|
|
||||||
close( obj->fd );
|
|
||||||
obj->fd = -1;
|
|
||||||
obj->select = -1;
|
|
||||||
active_users--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* change the fd and events of an object */
|
|
||||||
void change_select_fd( struct object *obj, int fd, int events )
|
|
||||||
{
|
|
||||||
int user = obj->select;
|
|
||||||
assert( poll_users[user] == obj );
|
|
||||||
pollfd[user].fd = fd;
|
|
||||||
pollfd[user].events = events;
|
|
||||||
obj->fd = fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the events that select waits for on this fd */
|
|
||||||
void set_select_events( struct object *obj, int 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add a timeout user */
|
|
||||||
struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
|
|
||||||
{
|
|
||||||
struct timeout_user *user;
|
|
||||||
struct timeout_user *pos;
|
|
||||||
|
|
||||||
if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
|
|
||||||
user->when = *when;
|
|
||||||
user->callback = func;
|
|
||||||
user->private = private;
|
|
||||||
|
|
||||||
/* Now insert it in the linked list */
|
|
||||||
|
|
||||||
for (pos = timeout_head; pos; pos = pos->next)
|
|
||||||
if (!time_before( &pos->when, when )) break;
|
|
||||||
|
|
||||||
if (pos) /* insert it before 'pos' */
|
|
||||||
{
|
|
||||||
if ((user->prev = pos->prev)) user->prev->next = user;
|
|
||||||
else timeout_head = user;
|
|
||||||
user->next = pos;
|
|
||||||
pos->prev = user;
|
|
||||||
}
|
|
||||||
else /* insert it at the tail */
|
|
||||||
{
|
|
||||||
user->next = NULL;
|
|
||||||
if (timeout_tail) timeout_tail->next = user;
|
|
||||||
else timeout_head = user;
|
|
||||||
user->prev = timeout_tail;
|
|
||||||
timeout_tail = user;
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove a timeout user */
|
|
||||||
void remove_timeout_user( struct timeout_user *user )
|
|
||||||
{
|
|
||||||
if (user->next) user->next->prev = user->prev;
|
|
||||||
else timeout_tail = user->prev;
|
|
||||||
if (user->prev) user->prev->next = user->next;
|
|
||||||
else timeout_head = user->next;
|
|
||||||
free( user );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add a timeout in milliseconds to an absolute time */
|
|
||||||
void add_timeout( struct timeval *when, int timeout )
|
|
||||||
{
|
|
||||||
if (timeout)
|
|
||||||
{
|
|
||||||
long sec = timeout / 1000;
|
|
||||||
if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
|
|
||||||
{
|
|
||||||
when->tv_usec -= 1000000;
|
|
||||||
when->tv_sec++;
|
|
||||||
}
|
|
||||||
when->tv_sec += sec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* handle the next expired timeout */
|
|
||||||
static void handle_timeout(void)
|
|
||||||
{
|
|
||||||
struct timeout_user *user = timeout_head;
|
|
||||||
timeout_head = user->next;
|
|
||||||
if (user->next) user->next->prev = user->prev;
|
|
||||||
else timeout_tail = user->prev;
|
|
||||||
user->callback( user->private );
|
|
||||||
free( user );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SIGHUP handler */
|
|
||||||
static void sighup_handler()
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_OBJECTS
|
|
||||||
dump_objects();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SIGTERM handler */
|
|
||||||
static void sigterm_handler()
|
|
||||||
{
|
|
||||||
flush_registry();
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SIGINT handler */
|
|
||||||
static void sigint_handler()
|
|
||||||
{
|
|
||||||
kill_all_processes( NULL, 1 );
|
|
||||||
flush_registry();
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* server main loop */
|
|
||||||
void select_loop(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
sigset_t sigset;
|
|
||||||
struct sigaction action;
|
|
||||||
|
|
||||||
/* block the signals we use */
|
|
||||||
sigemptyset( &sigset );
|
|
||||||
sigaddset( &sigset, SIGCHLD );
|
|
||||||
sigaddset( &sigset, SIGHUP );
|
|
||||||
sigaddset( &sigset, SIGINT );
|
|
||||||
sigaddset( &sigset, SIGQUIT );
|
|
||||||
sigaddset( &sigset, SIGTERM );
|
|
||||||
sigprocmask( SIG_BLOCK, &sigset, NULL );
|
|
||||||
|
|
||||||
/* set the handlers */
|
|
||||||
action.sa_mask = sigset;
|
|
||||||
action.sa_flags = 0;
|
|
||||||
action.sa_handler = sigchld_handler;
|
|
||||||
sigaction( SIGCHLD, &action, NULL );
|
|
||||||
action.sa_handler = sighup_handler;
|
|
||||||
sigaction( SIGHUP, &action, NULL );
|
|
||||||
action.sa_handler = sigint_handler;
|
|
||||||
sigaction( SIGINT, &action, NULL );
|
|
||||||
action.sa_handler = sigterm_handler;
|
|
||||||
sigaction( SIGQUIT, &action, NULL );
|
|
||||||
sigaction( SIGTERM, &action, NULL );
|
|
||||||
|
|
||||||
while (active_users)
|
|
||||||
{
|
|
||||||
long diff = -1;
|
|
||||||
if (timeout_head)
|
|
||||||
{
|
|
||||||
struct timeval now;
|
|
||||||
gettimeofday( &now, NULL );
|
|
||||||
while (timeout_head)
|
|
||||||
{
|
|
||||||
if (!time_before( &now, &timeout_head->when )) handle_timeout();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
diff = (timeout_head->when.tv_sec - now.tv_sec) * 1000
|
|
||||||
+ (timeout_head->when.tv_usec - now.tv_usec) / 1000;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!active_users) break; /* last user removed by a timeout */
|
|
||||||
}
|
|
||||||
|
|
||||||
sigprocmask( SIG_UNBLOCK, &sigset, NULL );
|
|
||||||
|
|
||||||
/* Note: we assume that the signal handlers do not manipulate the pollfd array
|
|
||||||
* or the timeout list, otherwise there is a race here.
|
|
||||||
*/
|
|
||||||
ret = poll( pollfd, nb_users, diff );
|
|
||||||
|
|
||||||
sigprocmask( SIG_BLOCK, &sigset, NULL );
|
|
||||||
|
|
||||||
if (ret > 0)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < nb_users; i++)
|
|
||||||
{
|
|
||||||
if (pollfd[i].revents)
|
|
||||||
{
|
|
||||||
fd_poll_event( poll_users[i], pollfd[i].revents );
|
|
||||||
if (!--ret) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -52,6 +52,7 @@
|
|||||||
#include "async.h"
|
#include "async.h"
|
||||||
|
|
||||||
static void serial_dump( struct object *obj, int verbose );
|
static void serial_dump( struct object *obj, int verbose );
|
||||||
|
static struct fd *serial_get_fd( struct object *obj );
|
||||||
static void serial_destroy(struct object *obj);
|
static void serial_destroy(struct object *obj);
|
||||||
|
|
||||||
static int serial_get_poll_events( struct fd *fd );
|
static int serial_get_poll_events( struct fd *fd );
|
||||||
@ -63,6 +64,7 @@ static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, in
|
|||||||
struct serial
|
struct serial
|
||||||
{
|
{
|
||||||
struct object obj;
|
struct object obj;
|
||||||
|
struct fd *fd;
|
||||||
unsigned int access;
|
unsigned int access;
|
||||||
unsigned int attrib;
|
unsigned int attrib;
|
||||||
|
|
||||||
@ -93,7 +95,7 @@ static const struct object_ops serial_ops =
|
|||||||
default_fd_remove_queue, /* remove_queue */
|
default_fd_remove_queue, /* remove_queue */
|
||||||
default_fd_signaled, /* signaled */
|
default_fd_signaled, /* signaled */
|
||||||
no_satisfied, /* satisfied */
|
no_satisfied, /* satisfied */
|
||||||
default_get_fd, /* get_fd */
|
serial_get_fd, /* get_fd */
|
||||||
serial_destroy /* destroy */
|
serial_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -148,7 +150,7 @@ static struct serial *create_serial( const char *nameptr, size_t len, unsigned i
|
|||||||
if(0>fcntl(fd, F_SETFL, 0))
|
if(0>fcntl(fd, F_SETFL, 0))
|
||||||
perror("fcntl");
|
perror("fcntl");
|
||||||
|
|
||||||
if ((serial = alloc_fd_object( &serial_ops, &serial_fd_ops, fd )))
|
if ((serial = alloc_object( &serial_ops )))
|
||||||
{
|
{
|
||||||
serial->attrib = attributes;
|
serial->attrib = attributes;
|
||||||
serial->access = access;
|
serial->access = access;
|
||||||
@ -162,10 +164,21 @@ static struct serial *create_serial( const char *nameptr, size_t len, unsigned i
|
|||||||
init_async_queue(&serial->read_q);
|
init_async_queue(&serial->read_q);
|
||||||
init_async_queue(&serial->write_q);
|
init_async_queue(&serial->write_q);
|
||||||
init_async_queue(&serial->wait_q);
|
init_async_queue(&serial->wait_q);
|
||||||
|
if (!(serial->fd = alloc_fd( &serial_fd_ops, fd, &serial->obj )))
|
||||||
|
{
|
||||||
|
release_object( serial );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct fd *serial_get_fd( struct object *obj )
|
||||||
|
{
|
||||||
|
struct serial *serial = (struct serial *)obj;
|
||||||
|
return (struct fd *)grab_object( serial->fd );
|
||||||
|
}
|
||||||
|
|
||||||
static void serial_destroy( struct object *obj)
|
static void serial_destroy( struct object *obj)
|
||||||
{
|
{
|
||||||
struct serial *serial = (struct serial *)obj;
|
struct serial *serial = (struct serial *)obj;
|
||||||
@ -173,16 +186,17 @@ static void serial_destroy( struct object *obj)
|
|||||||
destroy_async_queue(&serial->read_q);
|
destroy_async_queue(&serial->read_q);
|
||||||
destroy_async_queue(&serial->write_q);
|
destroy_async_queue(&serial->write_q);
|
||||||
destroy_async_queue(&serial->wait_q);
|
destroy_async_queue(&serial->wait_q);
|
||||||
|
if (serial->fd) release_object( serial->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_dump( struct object *obj, int verbose )
|
static void serial_dump( struct object *obj, int verbose )
|
||||||
{
|
{
|
||||||
struct serial *serial = (struct serial *)obj;
|
struct serial *serial = (struct serial *)obj;
|
||||||
assert( obj->ops == &serial_ops );
|
assert( obj->ops == &serial_ops );
|
||||||
fprintf( stderr, "Port fd=%p mask=%x\n", serial->obj.fd_obj, serial->eventmask );
|
fprintf( stderr, "Port fd=%p mask=%x\n", serial->fd, serial->eventmask );
|
||||||
}
|
}
|
||||||
|
|
||||||
struct serial *get_serial_obj( struct process *process, obj_handle_t handle, unsigned int access )
|
static struct serial *get_serial_obj( struct process *process, obj_handle_t handle, unsigned int access )
|
||||||
{
|
{
|
||||||
return (struct serial *)get_handle_obj( process, handle, access, &serial_ops );
|
return (struct serial *)get_handle_obj( process, handle, access, &serial_ops );
|
||||||
}
|
}
|
||||||
@ -249,7 +263,7 @@ static void serial_poll_event(struct fd *fd, int event)
|
|||||||
if(IS_READY(serial->wait_q) && (POLLIN & event) )
|
if(IS_READY(serial->wait_q) && (POLLIN & event) )
|
||||||
async_notify(serial->wait_q.head,STATUS_ALERTED);
|
async_notify(serial->wait_q.head,STATUS_ALERTED);
|
||||||
|
|
||||||
set_select_events( &serial->obj, serial_get_poll_events(fd) );
|
set_fd_events( fd, serial_get_poll_events(fd) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count)
|
static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count)
|
||||||
@ -310,7 +324,7 @@ static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, in
|
|||||||
else if ( async ) destroy_async ( async );
|
else if ( async ) destroy_async ( async );
|
||||||
else set_error ( STATUS_INVALID_PARAMETER );
|
else set_error ( STATUS_INVALID_PARAMETER );
|
||||||
|
|
||||||
set_select_events ( &serial->obj, serial_get_poll_events( fd ));
|
set_fd_events ( fd, serial_get_poll_events( fd ));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int serial_flush( struct fd *fd )
|
static int serial_flush( struct fd *fd )
|
||||||
|
24
server/smb.c
24
server/smb.c
@ -52,6 +52,7 @@
|
|||||||
#include "request.h"
|
#include "request.h"
|
||||||
|
|
||||||
static void smb_dump( struct object *obj, int verbose );
|
static void smb_dump( struct object *obj, int verbose );
|
||||||
|
static struct fd *smb_get_fd( struct object *obj );
|
||||||
static void smb_destroy(struct object *obj);
|
static void smb_destroy(struct object *obj);
|
||||||
|
|
||||||
static int smb_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags );
|
static int smb_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags );
|
||||||
@ -60,6 +61,7 @@ static int smb_get_poll_events( struct fd *fd );
|
|||||||
struct smb
|
struct smb
|
||||||
{
|
{
|
||||||
struct object obj;
|
struct object obj;
|
||||||
|
struct fd *fd;
|
||||||
unsigned int tree_id;
|
unsigned int tree_id;
|
||||||
unsigned int user_id;
|
unsigned int user_id;
|
||||||
unsigned int dialect;
|
unsigned int dialect;
|
||||||
@ -75,7 +77,7 @@ static const struct object_ops smb_ops =
|
|||||||
default_fd_remove_queue, /* remove_queue */
|
default_fd_remove_queue, /* remove_queue */
|
||||||
default_fd_signaled, /* signaled */
|
default_fd_signaled, /* signaled */
|
||||||
no_satisfied, /* satisfied */
|
no_satisfied, /* satisfied */
|
||||||
default_get_fd, /* get_fd */
|
smb_get_fd, /* get_fd */
|
||||||
smb_destroy /* destroy */
|
smb_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,20 +90,27 @@ static const struct fd_ops smb_fd_ops =
|
|||||||
no_queue_async /* queue_async */
|
no_queue_async /* queue_async */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct fd *smb_get_fd( struct object *obj )
|
||||||
|
{
|
||||||
|
struct smb *smb = (struct smb *)obj;
|
||||||
|
return (struct fd *)grab_object( smb->fd );
|
||||||
|
}
|
||||||
|
|
||||||
static void smb_destroy( struct object *obj)
|
static void smb_destroy( struct object *obj)
|
||||||
{
|
{
|
||||||
/* struct smb *smb = (struct smb *)obj; */
|
struct smb *smb = (struct smb *)obj;
|
||||||
assert( obj->ops == &smb_ops );
|
assert( obj->ops == &smb_ops );
|
||||||
|
if (smb->fd) release_object( smb->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smb_dump( struct object *obj, int verbose )
|
static void smb_dump( struct object *obj, int verbose )
|
||||||
{
|
{
|
||||||
struct smb *smb = (struct smb *)obj;
|
struct smb *smb = (struct smb *)obj;
|
||||||
assert( obj->ops == &smb_ops );
|
assert( obj->ops == &smb_ops );
|
||||||
fprintf( stderr, "Smb file fd=%p\n", smb->obj.fd_obj );
|
fprintf( stderr, "Smb file fd=%p\n", smb->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
struct smb *get_smb_obj( struct process *process, obj_handle_t handle, unsigned int access )
|
static struct smb *get_smb_obj( struct process *process, obj_handle_t handle, unsigned int access )
|
||||||
{
|
{
|
||||||
return (struct smb *)get_handle_obj( process, handle, access, &smb_ops );
|
return (struct smb *)get_handle_obj( process, handle, access, &smb_ops );
|
||||||
}
|
}
|
||||||
@ -158,7 +167,7 @@ DECL_HANDLER(create_smb)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
smb = alloc_fd_object( &smb_ops, &smb_fd_ops, fd );
|
smb = alloc_object( &smb_ops );
|
||||||
if (smb)
|
if (smb)
|
||||||
{
|
{
|
||||||
smb->tree_id = req->tree_id;
|
smb->tree_id = req->tree_id;
|
||||||
@ -166,6 +175,11 @@ DECL_HANDLER(create_smb)
|
|||||||
smb->dialect = req->dialect;
|
smb->dialect = req->dialect;
|
||||||
smb->file_id = req->file_id;
|
smb->file_id = req->file_id;
|
||||||
smb->offset = 0;
|
smb->offset = 0;
|
||||||
|
if (!(smb->fd = alloc_fd( &smb_fd_ops, fd, &smb->obj )))
|
||||||
|
{
|
||||||
|
release_object( smb );
|
||||||
|
return;
|
||||||
|
}
|
||||||
reply->handle = alloc_handle( current->process, smb, GENERIC_READ, 0);
|
reply->handle = alloc_handle( current->process, smb, GENERIC_READ, 0);
|
||||||
release_object( smb );
|
release_object( smb );
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ static struct snapshot *create_snapshot( process_id_t pid, int flags )
|
|||||||
else if (!(process = get_process_from_id( pid ))) return NULL;
|
else if (!(process = get_process_from_id( pid ))) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(snapshot = alloc_object( &snapshot_ops, -1 )))
|
if (!(snapshot = alloc_object( &snapshot_ops )))
|
||||||
{
|
{
|
||||||
if (process) release_object( process );
|
if (process) release_object( process );
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -65,11 +65,13 @@
|
|||||||
struct sock
|
struct sock
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
|
struct fd *fd; /* socket file descriptor */
|
||||||
unsigned int state; /* status bits */
|
unsigned int state; /* status bits */
|
||||||
unsigned int mask; /* event mask */
|
unsigned int mask; /* event mask */
|
||||||
unsigned int hmask; /* held (blocked) events */
|
unsigned int hmask; /* held (blocked) events */
|
||||||
unsigned int pmask; /* pending events */
|
unsigned int pmask; /* pending events */
|
||||||
unsigned int flags; /* socket flags */
|
unsigned int flags; /* socket flags */
|
||||||
|
int polling; /* is socket being polled? */
|
||||||
unsigned short type; /* socket type */
|
unsigned short type; /* socket type */
|
||||||
unsigned short family; /* socket family */
|
unsigned short family; /* socket family */
|
||||||
struct event *event; /* event object */
|
struct event *event; /* event object */
|
||||||
@ -84,6 +86,7 @@ struct sock
|
|||||||
|
|
||||||
static void sock_dump( struct object *obj, int verbose );
|
static void sock_dump( struct object *obj, int verbose );
|
||||||
static int sock_signaled( struct object *obj, struct thread *thread );
|
static int sock_signaled( struct object *obj, struct thread *thread );
|
||||||
|
static struct fd *sock_get_fd( struct object *obj );
|
||||||
static void sock_destroy( struct object *obj );
|
static void sock_destroy( struct object *obj );
|
||||||
|
|
||||||
static int sock_get_poll_events( struct fd *fd );
|
static int sock_get_poll_events( struct fd *fd );
|
||||||
@ -102,7 +105,7 @@ static const struct object_ops sock_ops =
|
|||||||
remove_queue, /* remove_queue */
|
remove_queue, /* remove_queue */
|
||||||
sock_signaled, /* signaled */
|
sock_signaled, /* signaled */
|
||||||
no_satisfied, /* satisfied */
|
no_satisfied, /* satisfied */
|
||||||
default_get_fd, /* get_fd */
|
sock_get_fd, /* get_fd */
|
||||||
sock_destroy /* destroy */
|
sock_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,19 +196,20 @@ void sock_init(void)
|
|||||||
|
|
||||||
static int sock_reselect( struct sock *sock )
|
static int sock_reselect( struct sock *sock )
|
||||||
{
|
{
|
||||||
int ev = sock_get_poll_events( sock->obj.fd_obj );
|
int ev = sock_get_poll_events( sock->fd );
|
||||||
|
|
||||||
if (debug_level)
|
if (debug_level)
|
||||||
fprintf(stderr,"sock_reselect(%p): new mask %x\n", sock, ev);
|
fprintf(stderr,"sock_reselect(%p): new mask %x\n", sock, ev);
|
||||||
|
|
||||||
if (sock->obj.select == -1) {
|
if (!sock->polling) /* FIXME: should find a better way to do this */
|
||||||
|
{
|
||||||
/* previously unconnected socket, is this reselect supposed to connect it? */
|
/* previously unconnected socket, is this reselect supposed to connect it? */
|
||||||
if (!(sock->state & ~FD_WINE_NONBLOCKING)) return 0;
|
if (!(sock->state & ~FD_WINE_NONBLOCKING)) return 0;
|
||||||
/* ok, it is, attach it to the wineserver's main poll loop */
|
/* ok, it is, attach it to the wineserver's main poll loop */
|
||||||
add_select_user( &sock->obj );
|
sock->polling = 1;
|
||||||
}
|
}
|
||||||
/* update condition mask */
|
/* update condition mask */
|
||||||
set_select_events( &sock->obj, ev );
|
set_fd_events( sock->fd, ev );
|
||||||
return ev;
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,11 +217,11 @@ static int sock_reselect( struct sock *sock )
|
|||||||
This function is used to signal pending events nevertheless */
|
This function is used to signal pending events nevertheless */
|
||||||
static void sock_try_event ( struct sock *sock, int event )
|
static void sock_try_event ( struct sock *sock, int event )
|
||||||
{
|
{
|
||||||
event = check_fd_events( sock->obj.fd_obj, event );
|
event = check_fd_events( sock->fd, event );
|
||||||
if (event)
|
if (event)
|
||||||
{
|
{
|
||||||
if ( debug_level ) fprintf ( stderr, "sock_try_event: %x\n", event );
|
if ( debug_level ) fprintf ( stderr, "sock_try_event: %x\n", event );
|
||||||
sock_poll_event ( sock->obj.fd_obj, event );
|
sock_poll_event ( sock->fd, event );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,7 +417,7 @@ static void sock_poll_event( struct fd *fd, int event )
|
|||||||
{
|
{
|
||||||
if ( debug_level )
|
if ( debug_level )
|
||||||
fprintf ( stderr, "removing socket %p from select loop\n", sock );
|
fprintf ( stderr, "removing socket %p from select loop\n", sock );
|
||||||
set_select_events( &sock->obj, -1 );
|
set_fd_events( sock->fd, -1 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sock_reselect( sock );
|
sock_reselect( sock );
|
||||||
@ -431,7 +435,7 @@ static void sock_dump( struct object *obj, int verbose )
|
|||||||
struct sock *sock = (struct sock *)obj;
|
struct sock *sock = (struct sock *)obj;
|
||||||
assert( obj->ops == &sock_ops );
|
assert( obj->ops == &sock_ops );
|
||||||
printf( "Socket fd=%p, state=%x, mask=%x, pending=%x, held=%x\n",
|
printf( "Socket fd=%p, state=%x, mask=%x, pending=%x, held=%x\n",
|
||||||
sock->obj.fd_obj, sock->state,
|
sock->fd, sock->state,
|
||||||
sock->mask, sock->pmask, sock->hmask );
|
sock->mask, sock->pmask, sock->hmask );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,7 +444,7 @@ static int sock_signaled( struct object *obj, struct thread *thread )
|
|||||||
struct sock *sock = (struct sock *)obj;
|
struct sock *sock = (struct sock *)obj;
|
||||||
assert( obj->ops == &sock_ops );
|
assert( obj->ops == &sock_ops );
|
||||||
|
|
||||||
return check_fd_events( sock->obj.fd_obj, sock_get_poll_events( sock->obj.fd_obj ) ) != 0;
|
return check_fd_events( sock->fd, sock_get_poll_events( sock->fd ) ) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sock_get_poll_events( struct fd *fd )
|
static int sock_get_poll_events( struct fd *fd )
|
||||||
@ -555,6 +559,12 @@ static void sock_queue_async(struct fd *fd, void *ptr, unsigned int status, int
|
|||||||
if ( pollev ) sock_try_event ( sock, pollev );
|
if ( pollev ) sock_try_event ( sock, pollev );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct fd *sock_get_fd( struct object *obj )
|
||||||
|
{
|
||||||
|
struct sock *sock = (struct sock *)obj;
|
||||||
|
return (struct fd *)grab_object( sock->fd );
|
||||||
|
}
|
||||||
|
|
||||||
static void sock_destroy( struct object *obj )
|
static void sock_destroy( struct object *obj )
|
||||||
{
|
{
|
||||||
struct sock *sock = (struct sock *)obj;
|
struct sock *sock = (struct sock *)obj;
|
||||||
@ -571,6 +581,7 @@ static void sock_destroy( struct object *obj )
|
|||||||
destroy_async_queue ( &sock->write_q );
|
destroy_async_queue ( &sock->write_q );
|
||||||
}
|
}
|
||||||
if (sock->event) release_object( sock->event );
|
if (sock->event) release_object( sock->event );
|
||||||
|
if (sock->fd) release_object( sock->fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a new and unconnected socket */
|
/* create a new and unconnected socket */
|
||||||
@ -587,12 +598,16 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
|
fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
|
||||||
if (!(sock = alloc_fd_object( &sock_ops, &sock_fd_ops, -1 ))) return NULL;
|
if (!(sock = alloc_object( &sock_ops )))
|
||||||
set_unix_fd( &sock->obj, sockfd );
|
{
|
||||||
|
close( sockfd );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
sock->state = (type != SOCK_STREAM) ? (FD_READ|FD_WRITE) : 0;
|
sock->state = (type != SOCK_STREAM) ? (FD_READ|FD_WRITE) : 0;
|
||||||
sock->mask = 0;
|
sock->mask = 0;
|
||||||
sock->hmask = 0;
|
sock->hmask = 0;
|
||||||
sock->pmask = 0;
|
sock->pmask = 0;
|
||||||
|
sock->polling = 0;
|
||||||
sock->flags = flags;
|
sock->flags = flags;
|
||||||
sock->type = type;
|
sock->type = type;
|
||||||
sock->family = family;
|
sock->family = family;
|
||||||
@ -601,6 +616,11 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
|
|||||||
sock->message = 0;
|
sock->message = 0;
|
||||||
sock->wparam = 0;
|
sock->wparam = 0;
|
||||||
sock->deferred = NULL;
|
sock->deferred = NULL;
|
||||||
|
if (!(sock->fd = alloc_fd( &sock_fd_ops, sockfd, &sock->obj )))
|
||||||
|
{
|
||||||
|
release_object( sock );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (sock->flags & WSA_FLAG_OVERLAPPED)
|
if (sock->flags & WSA_FLAG_OVERLAPPED)
|
||||||
{
|
{
|
||||||
init_async_queue (&sock->read_q);
|
init_async_queue (&sock->read_q);
|
||||||
@ -635,14 +655,15 @@ static struct sock *accept_socket( obj_handle_t handle )
|
|||||||
* return.
|
* return.
|
||||||
*/
|
*/
|
||||||
slen = sizeof(saddr);
|
slen = sizeof(saddr);
|
||||||
acceptfd = accept( get_unix_fd(sock->obj.fd_obj), &saddr, &slen);
|
acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen);
|
||||||
if (acceptfd==-1) {
|
if (acceptfd==-1) {
|
||||||
sock_set_error();
|
sock_set_error();
|
||||||
release_object( sock );
|
release_object( sock );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(acceptsock = alloc_fd_object( &sock_ops, &sock_fd_ops, acceptfd )))
|
if (!(acceptsock = alloc_object( &sock_ops )))
|
||||||
{
|
{
|
||||||
|
close( acceptfd );
|
||||||
release_object( sock );
|
release_object( sock );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -655,6 +676,7 @@ static struct sock *accept_socket( obj_handle_t handle )
|
|||||||
acceptsock->mask = sock->mask;
|
acceptsock->mask = sock->mask;
|
||||||
acceptsock->hmask = 0;
|
acceptsock->hmask = 0;
|
||||||
acceptsock->pmask = 0;
|
acceptsock->pmask = 0;
|
||||||
|
acceptsock->polling = 0;
|
||||||
acceptsock->type = sock->type;
|
acceptsock->type = sock->type;
|
||||||
acceptsock->family = sock->family;
|
acceptsock->family = sock->family;
|
||||||
acceptsock->event = NULL;
|
acceptsock->event = NULL;
|
||||||
@ -664,6 +686,12 @@ static struct sock *accept_socket( obj_handle_t handle )
|
|||||||
if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event );
|
if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event );
|
||||||
acceptsock->flags = sock->flags;
|
acceptsock->flags = sock->flags;
|
||||||
acceptsock->deferred = 0;
|
acceptsock->deferred = 0;
|
||||||
|
if (!(acceptsock->fd = alloc_fd( &sock_fd_ops, acceptfd, &acceptsock->obj )))
|
||||||
|
{
|
||||||
|
release_object( acceptsock );
|
||||||
|
release_object( sock );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if ( acceptsock->flags & WSA_FLAG_OVERLAPPED )
|
if ( acceptsock->flags & WSA_FLAG_OVERLAPPED )
|
||||||
{
|
{
|
||||||
init_async_queue ( &acceptsock->read_q );
|
init_async_queue ( &acceptsock->read_q );
|
||||||
|
@ -127,8 +127,9 @@ inline static void init_thread_structure( struct thread *thread )
|
|||||||
thread->req_toread = 0;
|
thread->req_toread = 0;
|
||||||
thread->reply_data = NULL;
|
thread->reply_data = NULL;
|
||||||
thread->reply_towrite = 0;
|
thread->reply_towrite = 0;
|
||||||
thread->reply_fd = -1;
|
thread->request_fd = NULL;
|
||||||
thread->wait_fd = -1;
|
thread->reply_fd = NULL;
|
||||||
|
thread->wait_fd = NULL;
|
||||||
thread->state = RUNNING;
|
thread->state = RUNNING;
|
||||||
thread->attached = 0;
|
thread->attached = 0;
|
||||||
thread->exit_code = 0;
|
thread->exit_code = 0;
|
||||||
@ -149,12 +150,11 @@ struct thread *create_thread( int fd, struct process *process )
|
|||||||
{
|
{
|
||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
|
|
||||||
if (!(thread = alloc_fd_object( &thread_ops, &thread_fd_ops, fd ))) return NULL;
|
if (!(thread = alloc_object( &thread_ops ))) return NULL;
|
||||||
|
|
||||||
init_thread_structure( thread );
|
init_thread_structure( thread );
|
||||||
|
|
||||||
thread->process = (struct process *)grab_object( process );
|
thread->process = (struct process *)grab_object( process );
|
||||||
thread->request_fd = fd;
|
|
||||||
if (!current) current = thread;
|
if (!current) current = thread;
|
||||||
|
|
||||||
if (!booting_thread) /* first thread ever */
|
if (!booting_thread) /* first thread ever */
|
||||||
@ -171,8 +171,13 @@ struct thread *create_thread( int fd, struct process *process )
|
|||||||
release_object( thread );
|
release_object( thread );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (!(thread->request_fd = alloc_fd( &thread_fd_ops, fd, &thread->obj )))
|
||||||
|
{
|
||||||
|
release_object( thread );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
set_select_events( &thread->obj, POLLIN ); /* start listening to events */
|
set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */
|
||||||
add_process_thread( thread->process, thread );
|
add_process_thread( thread->process, thread );
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
@ -198,9 +203,9 @@ static void cleanup_thread( struct thread *thread )
|
|||||||
while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
|
while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
|
||||||
if (thread->req_data) free( thread->req_data );
|
if (thread->req_data) free( thread->req_data );
|
||||||
if (thread->reply_data) free( thread->reply_data );
|
if (thread->reply_data) free( thread->reply_data );
|
||||||
if (thread->request_fd != -1) close( thread->request_fd );
|
if (thread->request_fd) release_object( thread->request_fd );
|
||||||
if (thread->reply_fd != -1) close( thread->reply_fd );
|
if (thread->reply_fd) release_object( thread->reply_fd );
|
||||||
if (thread->wait_fd != -1) close( thread->wait_fd );
|
if (thread->wait_fd) release_object( thread->wait_fd );
|
||||||
if (thread->hooks) release_object( thread->hooks );
|
if (thread->hooks) release_object( thread->hooks );
|
||||||
free_msg_queue( thread );
|
free_msg_queue( thread );
|
||||||
destroy_thread_windows( thread );
|
destroy_thread_windows( thread );
|
||||||
@ -214,9 +219,9 @@ static void cleanup_thread( struct thread *thread )
|
|||||||
}
|
}
|
||||||
thread->req_data = NULL;
|
thread->req_data = NULL;
|
||||||
thread->reply_data = NULL;
|
thread->reply_data = NULL;
|
||||||
thread->request_fd = -1;
|
thread->request_fd = NULL;
|
||||||
thread->reply_fd = -1;
|
thread->reply_fd = NULL;
|
||||||
thread->wait_fd = -1;
|
thread->wait_fd = NULL;
|
||||||
thread->hooks = NULL;
|
thread->hooks = NULL;
|
||||||
|
|
||||||
if (thread == booting_thread) /* killing booting thread */
|
if (thread == booting_thread) /* killing booting thread */
|
||||||
@ -449,7 +454,8 @@ static int send_thread_wakeup( struct thread *thread, void *cookie, int signaled
|
|||||||
|
|
||||||
reply.cookie = cookie;
|
reply.cookie = cookie;
|
||||||
reply.signaled = signaled;
|
reply.signaled = signaled;
|
||||||
if ((ret = write( thread->wait_fd, &reply, sizeof(reply) )) == sizeof(reply)) return 0;
|
if ((ret = write( get_unix_fd( thread->wait_fd ), &reply, sizeof(reply) )) == sizeof(reply))
|
||||||
|
return 0;
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
fatal_protocol_error( thread, "partial wakeup write %d\n", ret );
|
fatal_protocol_error( thread, "partial wakeup write %d\n", ret );
|
||||||
else if (errno == EPIPE)
|
else if (errno == EPIPE)
|
||||||
@ -738,9 +744,6 @@ void kill_thread( struct thread *thread, int violent_death )
|
|||||||
remove_process_thread( thread->process, thread );
|
remove_process_thread( thread->process, thread );
|
||||||
wake_up( &thread->obj, 0 );
|
wake_up( &thread->obj, 0 );
|
||||||
detach_thread( thread, violent_death ? SIGTERM : 0 );
|
detach_thread( thread, violent_death ? SIGTERM : 0 );
|
||||||
if (thread->request_fd == thread->obj.fd) thread->request_fd = -1;
|
|
||||||
if (thread->reply_fd == thread->obj.fd) thread->reply_fd = -1;
|
|
||||||
remove_select_user( &thread->obj );
|
|
||||||
cleanup_thread( thread );
|
cleanup_thread( thread );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
@ -828,11 +831,12 @@ DECL_HANDLER(init_thread)
|
|||||||
fatal_protocol_error( current, "bad wait fd\n" );
|
fatal_protocol_error( current, "bad wait fd\n" );
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
current->reply_fd = alloc_fd( &thread_fd_ops, reply_fd, ¤t->obj );
|
||||||
|
current->wait_fd = alloc_fd( &thread_fd_ops, wait_fd, ¤t->obj );
|
||||||
|
if (!current->reply_fd || !current->wait_fd) return;
|
||||||
|
|
||||||
current->unix_pid = req->unix_pid;
|
current->unix_pid = req->unix_pid;
|
||||||
current->teb = req->teb;
|
current->teb = req->teb;
|
||||||
current->reply_fd = reply_fd;
|
|
||||||
current->wait_fd = wait_fd;
|
|
||||||
|
|
||||||
if (current->suspend + current->process->suspend > 0) stop_thread( current );
|
if (current->suspend + current->process->suspend > 0) stop_thread( current );
|
||||||
if (current->process->running_threads > 1)
|
if (current->process->running_threads > 1)
|
||||||
|
@ -81,9 +81,9 @@ struct thread
|
|||||||
void *reply_data; /* variable-size data for reply */
|
void *reply_data; /* variable-size data for reply */
|
||||||
unsigned int reply_size; /* size of reply data */
|
unsigned int reply_size; /* size of reply data */
|
||||||
unsigned int reply_towrite; /* amount of data still to write in reply */
|
unsigned int reply_towrite; /* amount of data still to write in reply */
|
||||||
int request_fd; /* fd for receiving client requests */
|
struct fd *request_fd; /* fd for receiving client requests */
|
||||||
int reply_fd; /* fd to send a reply to a client */
|
struct fd *reply_fd; /* fd to send a reply to a client */
|
||||||
int wait_fd; /* fd to use to wake a sleeping client */
|
struct fd *wait_fd; /* fd to use to wake a sleeping client */
|
||||||
enum run_state state; /* running state */
|
enum run_state state; /* running state */
|
||||||
int attached; /* is thread attached with ptrace? */
|
int attached; /* is thread attached with ptrace? */
|
||||||
int exit_code; /* thread exit code */
|
int exit_code; /* thread exit code */
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
|
|
||||||
|
#include "file.h"
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user