* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
*/
-
+#define PERLIO_NOT_STDIO 0
#define WIN32_LEAN_AND_MEAN
#define WIN32IO_IS_STDIO
#include <tchar.h>
#endif
#include <winnt.h>
#include <io.h>
+#include <signal.h>
/* #include "config.h" */
-#define PERLIO_NOT_STDIO 0
#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
#define PerlIO FILE
#endif
/* it is a pseudo-forked child */
child = find_pseudo_pid(-pid);
if (child >= 0) {
- if (!sig)
- return 0;
hProcess = w32_pseudo_child_handles[child];
- if (TerminateThread(hProcess, sig)) {
- remove_dead_pseudo_process(child);
+ switch (sig) {
+ case 0:
+ /* "Does process exist?" use of kill */
return 0;
- }
+ case 9:
+ /* kill -9 style un-graceful exit */
+ if (TerminateThread(hProcess, sig)) {
+ remove_dead_pseudo_process(child);
+ return 0;
+ }
+ break;
+ default:
+ /* We fake signals to pseudo-processes using Win32 message queue */
+ if (PostThreadMessage(-pid,WM_USER,sig,0)) {
+ /* It might be us ... */
+ PERL_ASYNC_CHECK();
+ return 0;
+ }
+ break;
+ }
}
else if (IsWin95()) {
pid = -pid;
{
child = find_pid(pid);
if (child >= 0) {
- if (!sig)
+ hProcess = w32_child_handles[child];
+ switch(sig) {
+ case 0:
+ /* "Does process exist?" use of kill */
return 0;
- hProcess = w32_child_handles[child];
- if (TerminateProcess(hProcess, sig)) {
- remove_dead_process(child);
- return 0;
- }
+ case 2:
+ if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
+ return 0;
+ break;
+ default: /* For now be backwards compatible with perl5.6 */
+ case 9:
+ if (TerminateProcess(hProcess, sig)) {
+ remove_dead_process(child);
+ return 0;
+ }
+ break;
+ }
}
else {
alien_process:
hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
(IsWin95() ? -pid : pid));
if (hProcess) {
- if (!sig)
- return 0;
- if (TerminateProcess(hProcess, sig)) {
- CloseHandle(hProcess);
+ switch(sig) {
+ case 0:
+ /* "Does process exist?" use of kill */
return 0;
+ case 2:
+ if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
+ return 0;
+ break;
+ default: /* For now be backwards compatible with perl5.6 */
+ case 9:
+ if (TerminateProcess(hProcess, sig)) {
+ CloseHandle(hProcess);
+ return 0;
+ }
}
}
}
return -1;
}
-/*
- * File system stuff
- */
-
-DllExport unsigned int
-win32_sleep(unsigned int t)
-{
- Sleep(t*1000);
- return 0;
-}
-
DllExport int
win32_stat(const char *path, struct stat *sbuf)
{
return 0;
}
+/* Timing related stuff */
+
+DllExport int
+win32_async_check(pTHX)
+{
+ MSG msg;
+ int ours = 1;
+ /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
+ * and ignores window messages - should co-exist better with windows apps e.g. Tk
+ */
+ while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
+ switch(msg.message) {
+
+#if 0
+ /* Perhaps some other messages could map to signals ? ... */
+ case WM_CLOSE:
+ case WM_QUIT:
+ /* Treat WM_QUIT like SIGHUP? */
+ CALL_FPTR(PL_sighandlerp)(1);
+ break;
+#endif
+
+ /* We use WM_USER to fake kill() with other signals */
+ case WM_USER: {
+ CALL_FPTR(PL_sighandlerp)(msg.wParam);
+ break;
+ }
+
+ case WM_TIMER: {
+ /* alarm() is a one-shot but SetTimer() repeats so kill it */
+ if (w32_timerid) {
+ KillTimer(NULL,w32_timerid);
+ w32_timerid=0;
+ }
+ /* Now fake a call to signal handler */
+ CALL_FPTR(PL_sighandlerp)(14);
+ break;
+ }
+
+ /* Otherwise do normal Win32 thing - in case it is useful */
+ default:
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ ours = 0;
+ break;
+ }
+ }
+ w32_poll_count = 0;
+
+ /* Above or other stuff may have set a signal flag */
+ if (PL_sig_pending) {
+ despatch_signals();
+ }
+ return ours;
+}
+
+DllExport DWORD
+win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
+{
+ /* We may need several goes at this - so compute when we stop */
+ DWORD ticks = 0;
+ if (timeout != INFINITE) {
+ ticks = GetTickCount();
+ timeout += ticks;
+ }
+ while (1) {
+ DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
+ if (resultp)
+ *resultp = result;
+ if (result == WAIT_TIMEOUT) {
+ /* Ran out of time - explicit return of zero to avoid -ve if we
+ have scheduling issues
+ */
+ return 0;
+ }
+ if (timeout != INFINITE) {
+ ticks = GetTickCount();
+ }
+ if (result == WAIT_OBJECT_0 + count) {
+ /* Message has arrived - check it */
+ if (win32_async_check(aTHX)) {
+ /* was one of ours */
+ break;
+ }
+ }
+ else {
+ /* Not timeout or message - one of handles is ready */
+ break;
+ }
+ }
+ /* compute time left to wait */
+ ticks = timeout - ticks;
+ /* If we are past the end say zero */
+ return (ticks > 0) ? ticks : 0;
+}
+
int
win32_internal_wait(int *status, DWORD timeout)
{
#ifdef USE_ITHREADS
if (w32_num_pseudo_children) {
- waitcode = WaitForMultipleObjects(w32_num_pseudo_children,
- w32_pseudo_child_handles,
- FALSE,
- timeout);
+ win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
+ timeout, &waitcode);
/* Time out here if there are no other children to wait for. */
if (waitcode == WAIT_TIMEOUT) {
if (!w32_num_children) {
}
/* if a child exists, wait for it to die */
- waitcode = WaitForMultipleObjects(w32_num_children,
- w32_child_handles,
- FALSE,
- timeout);
+ win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
if (waitcode == WAIT_TIMEOUT) {
return 0;
}
child = find_pseudo_pid(-pid);
if (child >= 0) {
HANDLE hThread = w32_pseudo_child_handles[child];
- DWORD waitcode = WaitForSingleObject(hThread, timeout);
+ DWORD waitcode;
+ win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
if (waitcode == WAIT_TIMEOUT) {
return 0;
}
- else if (waitcode != WAIT_FAILED) {
+ else if (waitcode == WAIT_OBJECT_0) {
if (GetExitCodeThread(hThread, &waitcode)) {
*status = (int)((waitcode & 0xff) << 8);
retval = (int)w32_pseudo_child_pids[child];
child = find_pid(pid);
if (child >= 0) {
hProcess = w32_child_handles[child];
- waitcode = WaitForSingleObject(hProcess, timeout);
+ win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
if (waitcode == WAIT_TIMEOUT) {
return 0;
}
- else if (waitcode != WAIT_FAILED) {
+ else if (waitcode == WAIT_OBJECT_0) {
if (GetExitCodeProcess(hProcess, &waitcode)) {
*status = (int)((waitcode & 0xff) << 8);
retval = (int)w32_child_pids[child];
hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
(IsWin95() ? -pid : pid));
if (hProcess) {
- waitcode = WaitForSingleObject(hProcess, timeout);
+ win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
if (waitcode == WAIT_TIMEOUT) {
return 0;
}
- else if (waitcode != WAIT_FAILED) {
+ else if (waitcode == WAIT_OBJECT_0) {
if (GetExitCodeProcess(hProcess, &waitcode)) {
*status = (int)((waitcode & 0xff) << 8);
CloseHandle(hProcess);
return win32_internal_wait(status, INFINITE);
}
-#ifndef PERL_IMPLICIT_CONTEXT
-
-static UINT timerid = 0;
-
-static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
+DllExport unsigned int
+win32_sleep(unsigned int t)
{
dTHX;
- KillTimer(NULL,timerid);
- timerid=0;
- CALL_FPTR(PL_sighandlerp)(14);
+ /* Win32 times are in ms so *1000 in and /1000 out */
+ return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
}
-#endif /* !PERL_IMPLICIT_CONTEXT */
-
DllExport unsigned int
win32_alarm(unsigned int sec)
{
-#ifndef PERL_IMPLICIT_CONTEXT
/*
* the 'obvious' implentation is SetTimer() with a callback
* which does whatever receiving SIGALRM would do
* we cannot use SIGALRM even via raise() as it is not
* one of the supported codes in <signal.h>
- *
- * Snag is unless something is looking at the message queue
- * nothing happens :-(
*/
dTHX;
- if (sec)
- {
- timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
- if (!timerid)
- Perl_croak_nocontext("Cannot set timer");
- }
- else
- {
- if (timerid)
- {
- KillTimer(NULL,timerid);
- timerid=0;
- }
- }
-#endif /* !PERL_IMPLICIT_CONTEXT */
+ if (sec) {
+ w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
+ }
+ else {
+ if (w32_timerid) {
+ KillTimer(NULL,w32_timerid);
+ w32_timerid=0;
+ }
+ }
return 0;
}
ret = -1;
goto RETVAL;
}
+ /* Create a new process group so we can use GenerateConsoleCtrlEvent()
+ * in win32_kill()
+ */
+ create |= CREATE_NEW_PROCESS_GROUP;
/* FALL THROUGH */
+
case P_WAIT: /* synchronous execution */
break;
default: /* invalid mode */
}
else {
DWORD status;
- WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
+ win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
+ /* FIXME: if msgwait returned due to message perhaps forward the
+ "signal" to the process
+ */
GetExitCodeProcess(ProcessInformation.hProcess, &status);
ret = (int)status;
CloseHandle(ProcessInformation.hProcess);
*/
}
+PerlInterpreter *
+win32_signal_context(void)
+{
+ dTHX;
+ if (!my_perl) {
+ my_perl = PL_curinterp;
+ PERL_SET_THX(my_perl);
+ }
+ return my_perl;
+}
+
+BOOL WINAPI
+win32_ctrlhandler(DWORD dwCtrlType)
+{
+ dTHXa(PERL_GET_SIG_CONTEXT);
+
+ if (!my_perl)
+ return FALSE;
+
+ switch(dwCtrlType) {
+ case CTRL_CLOSE_EVENT:
+ /* A signal that the system sends to all processes attached to a console when
+ the user closes the console (either by choosing the Close command from the
+ console window's System menu, or by choosing the End Task command from the
+ Task List
+ */
+ CALL_FPTR(PL_sighandlerp)(1); /* SIGHUP */
+ return TRUE;
+
+ case CTRL_C_EVENT:
+ /* A CTRL+c signal was received */
+ CALL_FPTR(PL_sighandlerp)(SIGINT); /* SIGINT */
+ return TRUE;
+
+ case CTRL_BREAK_EVENT:
+ /* A CTRL+BREAK signal was received */
+ CALL_FPTR(PL_sighandlerp)(SIGBREAK); /* unix calls it SIGQUIT */
+ return TRUE;
+
+ case CTRL_LOGOFF_EVENT:
+ /* A signal that the system sends to all console processes when a user is logging
+ off. This signal does not indicate which user is logging off, so no
+ assumptions can be made.
+ */
+ break;
+ case CTRL_SHUTDOWN_EVENT:
+ /* A signal that the system sends to all console processes when the system is
+ shutting down.
+ */
+ CALL_FPTR(PL_sighandlerp)(SIGTERM);
+ return TRUE;
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+
+
void
Perl_win32_init(int *argcp, char ***argvp)
{
#ifdef HAVE_INTERP_INTERN
+
+static void
+win32_csighandler(int sig)
+{
+#if 0
+ dTHXa(PERL_GET_SIG_CONTEXT);
+ Perl_warn(aTHX_ "Got signal %d",sig);
+#endif
+ /* Does nothing */
+}
+
void
Perl_sys_intern_init(pTHX)
{
w32_num_pseudo_children = 0;
# endif
w32_init_socktype = 0;
+ w32_timerid = 0;
+ w32_poll_count = 0;
+ if (my_perl == PL_curinterp) {
+ /* Force C runtime signal stuff to set its console handler */
+ signal(SIGINT,&win32_csighandler);
+ signal(SIGBREAK,&win32_csighandler);
+ /* Push our handler on top */
+ SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
+ }
}
void
Safefree(w32_perlshell_vec);
/* NOTE: w32_fdpid is freed by sv_clean_all() */
Safefree(w32_children);
+ if (w32_timerid) {
+ KillTimer(NULL,w32_timerid);
+ w32_timerid=0;
+ }
+ if (my_perl == PL_curinterp) {
+ SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
+ }
# ifdef USE_ITHREADS
Safefree(w32_pseudo_children);
# endif
dst->pseudo_id = 0;
Newz(1313, dst->pseudo_children, 1, child_tab);
dst->thr_intern.Winit_socktype = 0;
+ dst->timerid = 0;
+ dst->poll_count = 0;
}
# endif /* USE_ITHREADS */
#endif /* HAVE_INTERP_INTERN */
GlobalFree((HGLOBAL)lpwStr);
}
+
+
+