fix Windows problems (maybe Vista-spcific) with FILE_TYPE_CHAR handles that can block on write
svn: r9893
This commit is contained in:
parent
b3dc8ca117
commit
584b4becf8
|
@ -148,6 +148,7 @@ typedef struct Win_FD_Output_Thread {
|
||||||
flush-checking thread to work, ready_sema indicates that a flush
|
flush-checking thread to work, ready_sema indicates that a flush
|
||||||
finished, and you_clean_up_sema is essentially a reference
|
finished, and you_clean_up_sema is essentially a reference
|
||||||
count */
|
count */
|
||||||
|
HANDLE thread;
|
||||||
} Win_FD_Output_Thread;
|
} Win_FD_Output_Thread;
|
||||||
|
|
||||||
int scheme_stupid_windows_machine;
|
int scheme_stupid_windows_machine;
|
||||||
|
@ -3437,9 +3438,13 @@ Scheme_Object *scheme_file_identity(int argc, Scheme_Object *argv[])
|
||||||
static int is_fd_terminal(int fd)
|
static int is_fd_terminal(int fd)
|
||||||
{
|
{
|
||||||
#if defined(WIN32_FD_HANDLES)
|
#if defined(WIN32_FD_HANDLES)
|
||||||
if (GetFileType((HANDLE)fd) == FILE_TYPE_CHAR)
|
if (GetFileType((HANDLE)fd) == FILE_TYPE_CHAR) {
|
||||||
return 1;
|
DWORD mode;
|
||||||
else
|
if (GetConsoleMode((HANDLE)fd, &mode))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return isatty(fd);
|
return isatty(fd);
|
||||||
|
@ -5713,8 +5718,7 @@ static long flush_fd(Scheme_Output_Port *op,
|
||||||
if (fop->regfile) {
|
if (fop->regfile) {
|
||||||
/* Regular files never block, so this code looks like the Unix
|
/* Regular files never block, so this code looks like the Unix
|
||||||
code. We've cheated in the make_fd proc and called
|
code. We've cheated in the make_fd proc and called
|
||||||
FILE_TYPE_CHAR devices (e.g., console) regular files,
|
consoles regular files, because they cannot block, either. */
|
||||||
because they cannot block, either. */
|
|
||||||
int orig_len;
|
int orig_len;
|
||||||
|
|
||||||
if (fop->textmode) {
|
if (fop->textmode) {
|
||||||
|
@ -5919,6 +5923,19 @@ static long flush_fd(Scheme_Output_Port *op,
|
||||||
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDWriter, oth, 0, &id);
|
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDWriter, oth, 0, &id);
|
||||||
|
|
||||||
scheme_remember_thread(h, 1);
|
scheme_remember_thread(h, 1);
|
||||||
|
|
||||||
|
/* scheme_remember_thread() is in charge of releasing h, so
|
||||||
|
duplicate it for use in closing: */
|
||||||
|
DuplicateHandle(GetCurrentProcess(),
|
||||||
|
h,
|
||||||
|
GetCurrentProcess(),
|
||||||
|
&h,
|
||||||
|
0,
|
||||||
|
FALSE,
|
||||||
|
DUPLICATE_SAME_ACCESS);
|
||||||
|
|
||||||
|
oth->thread = h;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5926,16 +5943,15 @@ static long flush_fd(Scheme_Output_Port *op,
|
||||||
done... */
|
done... */
|
||||||
|
|
||||||
if (!fop->oth->nonblocking) {
|
if (!fop->oth->nonblocking) {
|
||||||
/* This case is only for Win 95/98/Me anonymous pipes. We
|
/* This case is for Win 95/98/Me anonymous pipes and
|
||||||
haven't written anything yet! We write to a buffer read
|
character devices. We haven't written anything yet! We
|
||||||
by the other thread, and return -- the other thread takes
|
write to a buffer read by the other thread, and return --
|
||||||
care of writing. Thus, as long as there's room in the
|
the other thread takes care of writing. Thus, as long as
|
||||||
buffer, we don't block, and we can tell whether there's
|
there's room in the buffer, we don't block, and we can
|
||||||
room. Technical problem: if multiple ports are attched to
|
tell whether there's room. Technical problem: if multiple
|
||||||
the same underlying pipe (different handle, same
|
ports are attched to the same underlying pipe (different
|
||||||
"device"), the port writes can get out of order. We try
|
handle, same "device"), the port writes can get out of
|
||||||
to avoid the problem by sleeping --- it's only Win
|
order. We try to avoid the problem by sleeping. */
|
||||||
95/98/Me, after all. */
|
|
||||||
|
|
||||||
Win_FD_Output_Thread *oth = fop->oth;
|
Win_FD_Output_Thread *oth = fop->oth;
|
||||||
|
|
||||||
|
@ -6131,6 +6147,10 @@ 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)
|
||||||
{
|
{
|
||||||
|
@ -6161,6 +6181,29 @@ fd_close_output(Scheme_Output_Port *port)
|
||||||
|
|
||||||
#ifdef WINDOWS_FILE_HANDLES
|
#ifdef WINDOWS_FILE_HANDLES
|
||||||
if (fop->oth) {
|
if (fop->oth) {
|
||||||
|
static int tried_csi = 0;
|
||||||
|
static CSI_proc csi;
|
||||||
|
|
||||||
|
START_XFORM_SKIP;
|
||||||
|
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) {
|
||||||
|
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);
|
||||||
fop->oth->done = 1;
|
fop->oth->done = 1;
|
||||||
ReleaseSemaphore(fop->oth->work_sema, 1, NULL);
|
ReleaseSemaphore(fop->oth->work_sema, 1, NULL);
|
||||||
|
|
||||||
|
@ -6225,7 +6268,7 @@ make_fd_output_port(int fd, Scheme_Object *name, int regfile, int win_textmode,
|
||||||
|
|
||||||
#ifdef WINDOWS_FILE_HANDLES
|
#ifdef WINDOWS_FILE_HANDLES
|
||||||
/* Character devices can't block output, right? */
|
/* Character devices can't block output, right? */
|
||||||
if (GetFileType((HANDLE)fop->fd) == FILE_TYPE_CHAR)
|
if (is_fd_terminal(fop->fd))
|
||||||
regfile = 1;
|
regfile = 1;
|
||||||
/* The work thread is created on demand in fd_flush. */
|
/* The work thread is created on demand in fd_flush. */
|
||||||
#endif
|
#endif
|
||||||
|
@ -6305,8 +6348,9 @@ static long WindowsFDWriter(Win_FD_Output_Thread *oth)
|
||||||
ReleaseSemaphore(oth->lock_sema, 1, NULL);
|
ReleaseSemaphore(oth->lock_sema, 1, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Blocking mode. We do the writing work. This case is only for
|
/* Blocking mode. We do the writing work. This case is for
|
||||||
Win 95/98/Me anonymous pipes. */
|
Win 95/98/Me anonymous pipes and character devices (such
|
||||||
|
as LPT1). */
|
||||||
while (!oth->err_no) {
|
while (!oth->err_no) {
|
||||||
if (!more_work)
|
if (!more_work)
|
||||||
WaitForSingleObject(oth->work_sema, INFINITE);
|
WaitForSingleObject(oth->work_sema, INFINITE);
|
||||||
|
@ -6960,9 +7004,9 @@ static long mz_spawnv(char *command, const char * const *argv,
|
||||||
|
|
||||||
/* If none of the stdio handles are consoles, specifically
|
/* If none of the stdio handles are consoles, specifically
|
||||||
create the subprocess without a console: */
|
create the subprocess without a console: */
|
||||||
if ((GetFileType(startup.hStdInput) != FILE_TYPE_CHAR)
|
if (is_fd_terminal((int)startup.hStdInput)
|
||||||
&& (GetFileType(startup.hStdOutput) != FILE_TYPE_CHAR)
|
&& is_fd_terminal((int)startup.hStdOutput)
|
||||||
&& (GetFileType(startup.hStdError) != FILE_TYPE_CHAR))
|
&& is_fd_terminal((int)startup.hStdError))
|
||||||
cr_flag = CREATE_NO_WINDOW;
|
cr_flag = CREATE_NO_WINDOW;
|
||||||
else
|
else
|
||||||
cr_flag = 0;
|
cr_flag = 0;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user