Merge pull request #1429 from master

This commit is contained in:
Bernhard Miklautz 2013-08-26 20:19:55 +02:00
commit ec6b84fde4
4 changed files with 95 additions and 17 deletions

View File

@ -63,7 +63,9 @@ struct _SERIAL_DEVICE
SERIAL_TTY* tty; SERIAL_TTY* tty;
HANDLE thread; HANDLE thread;
HANDLE mthread;
HANDLE stopEvent; HANDLE stopEvent;
HANDLE newEvent;
wQueue* queue; wQueue* queue;
LIST* pending_irps; LIST* pending_irps;
@ -80,6 +82,7 @@ static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32
static void serial_check_for_events(SERIAL_DEVICE* serial); static void serial_check_for_events(SERIAL_DEVICE* serial);
static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp); static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp);
static BOOL serial_check_fds(SERIAL_DEVICE* serial); static BOOL serial_check_fds(SERIAL_DEVICE* serial);
static void* serial_thread_mfunc(void* arg);
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
{ {
@ -113,6 +116,18 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
else else
{ {
serial->tty = tty; serial->tty = tty;
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_NONE,
STATUS_CANCELLED);
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_READ,
STATUS_CANCELLED);
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_WRITE,
STATUS_CANCELLED);
serial->mthread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) serial_thread_mfunc, (void*) serial,
0, NULL);
DEBUG_SVC("%s(%d) created.", serial->path, FileId); DEBUG_SVC("%s(%d) created.", serial->path, FileId);
} }
@ -139,6 +154,11 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
{ {
DEBUG_SVC("%s(%d) closed.", serial->path, tty->id); DEBUG_SVC("%s(%d) closed.", serial->path, tty->id);
TerminateThread(serial->mthread, 0);
WaitForSingleObject(serial->mthread, INFINITE);
CloseHandle(serial->mthread);
serial->mthread = NULL;
serial_tty_free(tty); serial_tty_free(tty);
serial->tty = NULL; serial->tty = NULL;
} }
@ -318,36 +338,67 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
serial_check_for_events(serial); serial_check_for_events(serial);
} }
/* This thread is used as a workaround for the missing serial event
* support in WaitForMultipleObjects.
* It monitors the terminal for events and posts it in a supported
* form that WaitForMultipleObjects can use it. */
void* serial_thread_mfunc(void* arg)
{
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
while(1)
{
int sl;
fd_set rd;
if(!serial->tty || serial->tty->fd <= 0)
{
DEBUG_WARN("Monitor thread still running, but no terminal opened!");
sleep(1);
}
else
{
FD_ZERO(&rd);
FD_SET(serial->tty->fd, &rd);
sl = select(serial->tty->fd + 1, &rd, NULL, NULL, NULL);
if( sl > 0 )
SetEvent(serial->newEvent);
}
}
return NULL;
}
static void* serial_thread_func(void* arg) static void* serial_thread_func(void* arg)
{ {
IRP* irp; IRP* irp;
DWORD status; DWORD status;
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg; SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
HANDLE ev[] = {serial->stopEvent, Queue_Event(serial->queue)}; HANDLE ev[] = {serial->stopEvent, Queue_Event(serial->queue), serial->newEvent};
while (1) while (1)
{ {
status = WaitForMultipleObjects(2, ev, FALSE, 1); status = WaitForMultipleObjects(3, ev, FALSE, INFINITE);
if (WAIT_OBJECT_0 == status) if (WAIT_OBJECT_0 == status)
break; break;
else if (status == WAIT_OBJECT_0 + 1)
serial->nfds = 1;
FD_ZERO(&serial->read_fds);
FD_ZERO(&serial->write_fds);
serial->tv.tv_sec = 0;
serial->tv.tv_usec = 0;
serial->select_timeout = 0;
if (status == WAIT_OBJECT_0 + 1)
{ {
FD_ZERO(&serial->read_fds);
FD_ZERO(&serial->write_fds);
serial->tv.tv_sec = 0;
serial->tv.tv_usec = 0;
serial->select_timeout = 0;
if ((irp = (IRP*) Queue_Dequeue(serial->queue))) if ((irp = (IRP*) Queue_Dequeue(serial->queue)))
serial_process_irp(serial, irp); serial_process_irp(serial, irp);
continue;
} }
else if (status == WAIT_OBJECT_0 + 2)
ResetEvent(serial->newEvent);
serial_check_fds(serial); if(serial->tty)
serial_check_fds(serial);
} }
return NULL; return NULL;
@ -368,6 +419,12 @@ static void serial_free(DEVICE* device)
/* Stop thread */ /* Stop thread */
SetEvent(serial->stopEvent); SetEvent(serial->stopEvent);
if(serial->mthread)
{
TerminateThread(serial->mthread, 0);
WaitForSingleObject(serial->mthread, INFINITE);
CloseHandle(serial->mthread);
}
WaitForSingleObject(serial->thread, INFINITE); WaitForSingleObject(serial->thread, INFINITE);
serial_tty_free(serial->tty); serial_tty_free(serial->tty);
@ -377,6 +434,7 @@ static void serial_free(DEVICE* device)
Queue_Free(serial->queue); Queue_Free(serial->queue);
list_free(serial->pending_irps); list_free(serial->pending_irps);
CloseHandle(serial->stopEvent); CloseHandle(serial->stopEvent);
CloseHandle(serial->newEvent);
CloseHandle(serial->thread); CloseHandle(serial->thread);
free(serial); free(serial);
} }
@ -673,6 +731,13 @@ static BOOL serial_check_fds(SERIAL_DEVICE* serial)
if (list_size(serial->pending_irps) == 0) if (list_size(serial->pending_irps) == 0)
return 1; return 1;
FD_ZERO(&serial->read_fds);
FD_ZERO(&serial->write_fds);
serial->tv.tv_sec = 0;
serial->tv.tv_usec = 0;
serial->select_timeout = 0;
serial_set_fds(serial); serial_set_fds(serial);
DEBUG_SVC("waiting %lu %lu", serial->tv.tv_sec, serial->tv.tv_usec); DEBUG_SVC("waiting %lu %lu", serial->tv.tv_sec, serial->tv.tv_usec);
@ -739,11 +804,13 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
serial->pending_irps = list_new(); serial->pending_irps = list_new();
serial->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); serial->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
serial->newEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial);
serial->thread = CreateThread(NULL, 0, serial->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL); (LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL);
serial->mthread = NULL;
} }
return 0; return 0;

View File

@ -128,7 +128,7 @@ static void* smartcard_thread_func(void* arg)
while (1) while (1)
{ {
DWORD status = WaitForSingleObject(2, ev, FALSE, INFINITE); DWORD status = WaitForMultipleObjects(2, ev, FALSE, INFINITE);
if (status == WAIT_OBJECT_0 + 1) if (status == WAIT_OBJECT_0 + 1)
break; break;

View File

@ -18,6 +18,15 @@
set(MODULE_NAME "winpr-synch") set(MODULE_NAME "winpr-synch")
set(MODULE_PREFIX "WINPR_SYNCH") set(MODULE_PREFIX "WINPR_SYNCH")
INCLUDE (CheckLibraryExists)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
check_library_exists(pthread pthread_tryjoin_np "" HAVE_PTHREAD_GNU_EXT)
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
if(HAVE_PTHREAD_GNU_EXT)
add_definitions(-D_GNU_SOURCE -DHAVE_PTHREAD_GNU_EXT)
endif(HAVE_PTHREAD_GNU_EXT)
include_directories(../thread) include_directories(../thread)
set(${MODULE_PREFIX}_SRCS set(${MODULE_PREFIX}_SRCS

View File

@ -77,7 +77,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
{ {
if (dwMilliseconds != INFINITE) if (dwMilliseconds != INFINITE)
{ {
#if _GNU_SOURCE #if HAVE_PTHREAD_GNU_EXT
struct timespec timeout; struct timespec timeout;
clock_gettime(CLOCK_REALTIME, &timeout); clock_gettime(CLOCK_REALTIME, &timeout);
@ -105,6 +105,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
mutex = (WINPR_MUTEX*) Object; mutex = (WINPR_MUTEX*) Object;
#if HAVE_PTHREAD_GNU_EXT
if (dwMilliseconds != INFINITE) if (dwMilliseconds != INFINITE)
{ {
struct timespec timeout; struct timespec timeout;
@ -115,6 +116,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
pthread_mutex_timedlock(&mutex->mutex, &timeout); pthread_mutex_timedlock(&mutex->mutex, &timeout);
} }
else else
#endif
pthread_mutex_lock(&mutex->mutex); pthread_mutex_lock(&mutex->mutex);
} }
else if (Type == HANDLE_TYPE_EVENT) else if (Type == HANDLE_TYPE_EVENT)