avoid having MzScheme get stuck on pipes when CancelSynchronizedIo is not available
svn: r12060
This commit is contained in:
parent
2288db4fc9
commit
02fbdf09b1
|
@ -122,11 +122,15 @@ typedef struct Win_FD_Input_Thread {
|
||||||
/* This is malloced for use in a Win32 thread */
|
/* This is malloced for use in a Win32 thread */
|
||||||
HANDLE fd;
|
HANDLE fd;
|
||||||
volatile int avail, err, checking;
|
volatile int avail, err, checking;
|
||||||
|
int *refcount;
|
||||||
HANDLE eof;
|
HANDLE eof;
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
HANDLE checking_sema, ready_sema, you_clean_up_sema;
|
HANDLE checking_sema, ready_sema, you_clean_up_sema;
|
||||||
|
HANDLE thread;
|
||||||
} Win_FD_Input_Thread;
|
} Win_FD_Input_Thread;
|
||||||
|
|
||||||
|
static HANDLE refcount_sema;
|
||||||
|
|
||||||
typedef struct Win_FD_Output_Thread {
|
typedef struct Win_FD_Output_Thread {
|
||||||
/* This is malloced for use in a Win32 thread */
|
/* This is malloced for use in a Win32 thread */
|
||||||
HANDLE fd;
|
HANDLE fd;
|
||||||
|
@ -144,6 +148,7 @@ typedef struct Win_FD_Output_Thread {
|
||||||
volatile int done, err_no;
|
volatile int done, err_no;
|
||||||
volatile unsigned int buflen, bufstart, bufend; /* used for blocking, only */
|
volatile unsigned int buflen, bufstart, bufend; /* used for blocking, only */
|
||||||
unsigned char *buffer; /* used for blocking, only */
|
unsigned char *buffer; /* used for blocking, only */
|
||||||
|
int *refcount;
|
||||||
HANDLE lock_sema, work_sema, ready_sema, you_clean_up_sema;
|
HANDLE lock_sema, work_sema, ready_sema, you_clean_up_sema;
|
||||||
/* lock_sema protects the fields, work_sema starts the flush or
|
/* lock_sema protects the fields, work_sema starts the flush or
|
||||||
flush-checking thread to work, ready_sema indicates that a flush
|
flush-checking thread to work, ready_sema indicates that a flush
|
||||||
|
@ -187,6 +192,59 @@ typedef struct Scheme_Subprocess {
|
||||||
# define MZ_FDS
|
# define MZ_FDS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/******************** refcounts ********************/
|
||||||
|
|
||||||
|
#ifdef WINDOWS_FILE_HANDLES
|
||||||
|
|
||||||
|
static int *malloc_refcount()
|
||||||
|
{
|
||||||
|
if (!refcount_sema)
|
||||||
|
refcount_sema = CreateSemaphore(NULL, 1, 1, NULL);
|
||||||
|
|
||||||
|
return (int *)malloc(sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MZ_XFORM
|
||||||
|
START_XFORM_SKIP;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int dec_refcount(int *refcount)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!refcount)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
WaitForSingleObject(refcount_sema, INFINITE);
|
||||||
|
*refcount -= 1;
|
||||||
|
rc = *refcount;
|
||||||
|
ReleaseSemaphore(refcount_sema, 1, NULL);
|
||||||
|
|
||||||
|
if (!rc) free(refcount);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MZ_XFORM
|
||||||
|
END_XFORM_SKIP;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int *malloc_refcount()
|
||||||
|
{
|
||||||
|
return (int *)scheme_malloc_atomic(sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dec_refcount(int *refcount)
|
||||||
|
{
|
||||||
|
if (!refcount)
|
||||||
|
return 0;
|
||||||
|
*refcont -= 1;
|
||||||
|
return *refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/******************** file-descriptor I/O ********************/
|
/******************** file-descriptor I/O ********************/
|
||||||
|
|
||||||
|
@ -4532,6 +4590,26 @@ scheme_make_file_input_port(FILE *fp)
|
||||||
# ifdef WINDOWS_FILE_HANDLES
|
# ifdef WINDOWS_FILE_HANDLES
|
||||||
static long WindowsFDReader(Win_FD_Input_Thread *th);
|
static long WindowsFDReader(Win_FD_Input_Thread *th);
|
||||||
static void WindowsFDICleanup(Win_FD_Input_Thread *th);
|
static void WindowsFDICleanup(Win_FD_Input_Thread *th);
|
||||||
|
typedef BOOL (WINAPI* CSI_proc)(HANDLE);
|
||||||
|
|
||||||
|
static CSI_proc get_csi(void)
|
||||||
|
{
|
||||||
|
static int tried_csi = 0;
|
||||||
|
static CSI_proc csi;
|
||||||
|
|
||||||
|
START_XFORM_SKIP;
|
||||||
|
if (!tried_csi) {
|
||||||
|
HMODULE hm;
|
||||||
|
hm = LoadLibrary("kernel32.dll");
|
||||||
|
if (hm)
|
||||||
|
csi = (CSI_proc)GetProcAddress(hm, "CancelSynchronousIo");
|
||||||
|
else
|
||||||
|
csi = NULL;
|
||||||
|
tried_csi = 1;
|
||||||
|
}
|
||||||
|
END_XFORM_SKIP;
|
||||||
|
return csi;
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* forward decl: */
|
/* forward decl: */
|
||||||
|
@ -4914,11 +4992,10 @@ fd_close_input(Scheme_Input_Port *port)
|
||||||
|
|
||||||
fip = (Scheme_FD *)port->port_data;
|
fip = (Scheme_FD *)port->port_data;
|
||||||
|
|
||||||
if (fip->refcount)
|
|
||||||
*fip->refcount -= 1;
|
|
||||||
|
|
||||||
#ifdef WINDOWS_FILE_HANDLES
|
#ifdef WINDOWS_FILE_HANDLES
|
||||||
if (fip->th) {
|
if (fip->th) {
|
||||||
|
CSI_proc csi;
|
||||||
|
|
||||||
/* -1 for checking means "shut down" */
|
/* -1 for checking means "shut down" */
|
||||||
fip->th->checking = -1;
|
fip->th->checking = -1;
|
||||||
ReleaseSemaphore(fip->th->checking_sema, 1, NULL);
|
ReleaseSemaphore(fip->th->checking_sema, 1, NULL);
|
||||||
|
@ -4928,25 +5005,40 @@ fd_close_input(Scheme_Input_Port *port)
|
||||||
fip->th->eof = NULL;
|
fip->th->eof = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
csi = get_csi();
|
||||||
|
if (csi) {
|
||||||
|
/* Helps thread wake up. Otherwise, it's possible for the
|
||||||
|
thread to stay stuck trying to read, in which case the
|
||||||
|
file handle (probably a pipe) doesn't get closed. */
|
||||||
|
csi(fip->th->thread);
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to get out of cleaning up the records (since they can't be
|
/* Try to get out of cleaning up the records (since they can't be
|
||||||
cleaned until the thread is also done: */
|
cleaned until the thread is also done: */
|
||||||
if (WaitForSingleObject(fip->th->you_clean_up_sema, 0) != WAIT_OBJECT_0) {
|
if (WaitForSingleObject(fip->th->you_clean_up_sema, 0) != WAIT_OBJECT_0) {
|
||||||
/* The other thread exited and left us with clean-up: */
|
/* The other thread exited and left us with clean-up: */
|
||||||
WindowsFDICleanup(fip->th);
|
WindowsFDICleanup(fip->th);
|
||||||
} /* otherwise, thread is responsible for clean-up */
|
} /* otherwise, thread is responsible for clean-up */
|
||||||
}
|
} else {
|
||||||
if (!fip->refcount || !*fip->refcount) {
|
int rc;
|
||||||
CloseHandle((HANDLE)fip->fd);
|
rc = dec_refcount(fip->refcount);
|
||||||
--scheme_file_open_count;
|
if (!rc) {
|
||||||
|
CloseHandle((HANDLE)fip->fd);
|
||||||
|
--scheme_file_open_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (!fip->refcount || !*fip->refcount) {
|
{
|
||||||
int cr;
|
int rc;
|
||||||
do {
|
rc = dec_refcount(fip->refcount);
|
||||||
cr = close(fip->fd);
|
if (!rc) {
|
||||||
} while ((cr == -1) && (errno == EINTR));
|
int cr;
|
||||||
--scheme_file_open_count;
|
do {
|
||||||
}
|
cr = close(fip->fd);
|
||||||
|
} while ((cr == -1) && (errno == EINTR));
|
||||||
|
--scheme_file_open_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5088,9 +5180,12 @@ make_fd_input_port(int fd, Scheme_Object *name, int regfile, int win_textmode, i
|
||||||
th->ready_sema = sm;
|
th->ready_sema = sm;
|
||||||
sm = CreateSemaphore(NULL, 1, 1, NULL);
|
sm = CreateSemaphore(NULL, 1, 1, NULL);
|
||||||
th->you_clean_up_sema = sm;
|
th->you_clean_up_sema = sm;
|
||||||
|
th->refcount = refcount;
|
||||||
|
|
||||||
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDReader, th, 0, &id);
|
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDReader, th, 0, &id);
|
||||||
|
|
||||||
|
th->thread = h;
|
||||||
|
|
||||||
scheme_remember_thread(h, 1);
|
scheme_remember_thread(h, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -5161,9 +5256,15 @@ static long WindowsFDReader(Win_FD_Input_Thread *th)
|
||||||
|
|
||||||
static void WindowsFDICleanup(Win_FD_Input_Thread *th)
|
static void WindowsFDICleanup(Win_FD_Input_Thread *th)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
CloseHandle(th->checking_sema);
|
CloseHandle(th->checking_sema);
|
||||||
CloseHandle(th->ready_sema);
|
CloseHandle(th->ready_sema);
|
||||||
CloseHandle(th->you_clean_up_sema);
|
CloseHandle(th->you_clean_up_sema);
|
||||||
|
|
||||||
|
rc = dec_refcount(th->refcount);
|
||||||
|
if (!rc) CloseHandle(th->fd);
|
||||||
|
|
||||||
free(th->buffer);
|
free(th->buffer);
|
||||||
free(th);
|
free(th);
|
||||||
}
|
}
|
||||||
|
@ -5906,6 +6007,7 @@ static long flush_fd(Scheme_Output_Port *op,
|
||||||
oth->ready_sema = sm;
|
oth->ready_sema = sm;
|
||||||
sm = CreateSemaphore(NULL, 1, 1, NULL);
|
sm = CreateSemaphore(NULL, 1, 1, NULL);
|
||||||
oth->you_clean_up_sema = sm;
|
oth->you_clean_up_sema = sm;
|
||||||
|
oth->refcount = fop->refcount;
|
||||||
|
|
||||||
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDWriter, oth, 0, &id);
|
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDWriter, oth, 0, &id);
|
||||||
|
|
||||||
|
@ -6134,10 +6236,6 @@ fd_write_string(Scheme_Output_Port *port,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WINDOWS_FILE_HANDLES
|
|
||||||
typedef BOOL (WINAPI* CSI_proc)(HANDLE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fd_close_output(Scheme_Output_Port *port)
|
fd_close_output(Scheme_Output_Port *port)
|
||||||
{
|
{
|
||||||
|
@ -6163,32 +6261,15 @@ fd_close_output(Scheme_Output_Port *port)
|
||||||
if (port->closed)
|
if (port->closed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fop->refcount)
|
|
||||||
*fop->refcount -= 1;
|
|
||||||
|
|
||||||
#ifdef WINDOWS_FILE_HANDLES
|
#ifdef WINDOWS_FILE_HANDLES
|
||||||
if (fop->oth) {
|
if (fop->oth) {
|
||||||
static int tried_csi = 0;
|
CSI_proc csi;
|
||||||
static CSI_proc csi;
|
|
||||||
|
|
||||||
START_XFORM_SKIP;
|
csi = get_csi();
|
||||||
if (!tried_csi) {
|
|
||||||
HMODULE hm;
|
|
||||||
hm = LoadLibrary("kernel32.dll");
|
|
||||||
if (hm)
|
|
||||||
csi = (BOOL (WINAPI*)(HANDLE))GetProcAddress(hm, "CancelSynchronousIo");
|
|
||||||
else
|
|
||||||
csi = NULL;
|
|
||||||
tried_csi = 1;
|
|
||||||
}
|
|
||||||
END_XFORM_SKIP;
|
|
||||||
|
|
||||||
if (csi) {
|
if (csi) {
|
||||||
|
/* See also call to csi in fd_close_input */
|
||||||
csi(fop->oth->thread);
|
csi(fop->oth->thread);
|
||||||
/* We're hoping that if CancelSyncrhonousIo isn't available, that
|
|
||||||
CloseHandle() will work, or that WriteFile() didn't block after
|
|
||||||
all (which seems to be the case with pre-Vista FILE_TYPE_CHAR
|
|
||||||
handles). */
|
|
||||||
}
|
}
|
||||||
CloseHandle(fop->oth->thread);
|
CloseHandle(fop->oth->thread);
|
||||||
fop->oth->done = 1;
|
fop->oth->done = 1;
|
||||||
|
@ -6200,19 +6281,27 @@ fd_close_output(Scheme_Output_Port *port)
|
||||||
WindowsFDOCleanup(fop->oth);
|
WindowsFDOCleanup(fop->oth);
|
||||||
} /* otherwise, thread is responsible for clean-up */
|
} /* otherwise, thread is responsible for clean-up */
|
||||||
fop->oth = NULL;
|
fop->oth = NULL;
|
||||||
}
|
} else {
|
||||||
if (!fop->refcount || !*fop->refcount) {
|
int rc;
|
||||||
CloseHandle((HANDLE)fop->fd);
|
rc = dec_refcount(fop->refcount);
|
||||||
--scheme_file_open_count;
|
if (!rc) {
|
||||||
|
CloseHandle((HANDLE)fop->fd);
|
||||||
|
--scheme_file_open_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (!fop->refcount || !*fop->refcount) {
|
{
|
||||||
int cr;
|
int rc;
|
||||||
do {
|
rc = dec_refcount(fop->refcount);
|
||||||
cr = close(fop->fd);
|
|
||||||
} while ((cr == -1) && (errno == EINTR));
|
if (!rc) {
|
||||||
--scheme_file_open_count;
|
int cr;
|
||||||
}
|
do {
|
||||||
|
cr = close(fop->fd);
|
||||||
|
} while ((cr == -1) && (errno == EINTR));
|
||||||
|
--scheme_file_open_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6290,7 +6379,7 @@ make_fd_output_port(int fd, Scheme_Object *name, int regfile, int win_textmode,
|
||||||
if (and_read) {
|
if (and_read) {
|
||||||
int *rc;
|
int *rc;
|
||||||
Scheme_Object *a[2];
|
Scheme_Object *a[2];
|
||||||
rc = (int *)scheme_malloc_atomic(sizeof(int));
|
rc = malloc_refcount();
|
||||||
*rc = 2;
|
*rc = 2;
|
||||||
fop->refcount = rc;
|
fop->refcount = rc;
|
||||||
a[1] = the_port;
|
a[1] = the_port;
|
||||||
|
@ -6382,9 +6471,15 @@ static long WindowsFDWriter(Win_FD_Output_Thread *oth)
|
||||||
|
|
||||||
static void WindowsFDOCleanup(Win_FD_Output_Thread *oth)
|
static void WindowsFDOCleanup(Win_FD_Output_Thread *oth)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
CloseHandle(oth->lock_sema);
|
CloseHandle(oth->lock_sema);
|
||||||
CloseHandle(oth->work_sema);
|
CloseHandle(oth->work_sema);
|
||||||
CloseHandle(oth->you_clean_up_sema);
|
CloseHandle(oth->you_clean_up_sema);
|
||||||
|
|
||||||
|
rc = dec_refcount(oth->refcount);
|
||||||
|
if (!rc) CloseHandle(oth->fd);
|
||||||
|
|
||||||
if (oth->buffer)
|
if (oth->buffer)
|
||||||
free(oth->buffer);
|
free(oth->buffer);
|
||||||
free(oth);
|
free(oth);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user