summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorJan Dubois <jand@activestate.com>2005-12-16 07:12:00 +0000
committerRafael Garcia-Suarez <rgarciasuarez@gmail.com>2005-12-16 21:13:37 +0000
commitaeecf691f59fe1423b7011655dd5de7d5fbd2192 (patch)
treec9ef1f79b643133f95c8a03c1820e666397dfe08 /win32
parent3043b442861dc32a5941608838b57d2e089a7e25 (diff)
downloadperl-aeecf691f59fe1423b7011655dd5de7d5fbd2192.tar.gz
RE: PeekMessage() call in win32\win32.c win32_async_check
Message-ID: <015901c60207$abd64210$d563a8c0@candy> (Without the proposed alarm.t test) p4raw-id: //depot/perl@26379
Diffstat (limited to 'win32')
-rw-r--r--win32/perlhost.h12
-rw-r--r--win32/win32.c238
-rw-r--r--win32/win32.h25
3 files changed, 172 insertions, 103 deletions
diff --git a/win32/perlhost.h b/win32/perlhost.h
index 92d575795c..e2227e358f 100644
--- a/win32/perlhost.h
+++ b/win32/perlhost.h
@@ -1693,6 +1693,7 @@ win32_start_child(LPVOID arg)
PerlInterpreter *my_perl = (PerlInterpreter*)arg;
GV *tmpgv;
int status;
+ HWND parent_message_hwnd;
#ifdef PERL_SYNC_FORK
static long sync_fork_id = 0;
long id = ++sync_fork_id;
@@ -1723,6 +1724,12 @@ win32_start_child(LPVOID arg)
hv_clear(PL_pidstatus);
#endif
+ /* create message window and tell parent about it */
+ parent_message_hwnd = w32_message_hwnd;
+ w32_message_hwnd = win32_create_message_window();
+ if (parent_message_hwnd != NULL)
+ PostMessage(parent_message_hwnd, WM_USER_MESSAGE, w32_pseudo_id, (LONG)w32_message_hwnd);
+
/* push a zero on the stack (we are the child) */
{
dSP;
@@ -1826,6 +1833,11 @@ PerlProcFork(struct IPerlProc* piPerl)
id = win32_start_child((LPVOID)new_perl);
PERL_SET_THX(aTHX);
# else
+ if (w32_message_hwnd == INVALID_HANDLE_VALUE)
+ w32_message_hwnd = win32_create_message_window();
+ new_perl->Isys_intern.message_hwnd = w32_message_hwnd;
+ w32_pseudo_child_message_hwnds[w32_num_pseudo_children] =
+ (w32_message_hwnd == NULL) ? NULL : INVALID_HANDLE_VALUE;
# ifdef USE_RTL_THREAD_API
handle = (HANDLE)_beginthreadex((void*)NULL, 0, win32_start_child,
(void*)new_perl, 0, (unsigned*)&id);
diff --git a/win32/win32.c b/win32/win32.c
index 56b5da15ea..b09ae94a9f 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -15,6 +15,9 @@
#define Win32_Winsock
#endif
#include <windows.h>
+#ifndef HWND_MESSAGE
+# define HWND_MESSAGE ((HWND)-3)
+#endif
/* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */
#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
# include <shellapi.h>
@@ -113,7 +116,7 @@ HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
char w32_module_name[MAX_PATH+1];
END_EXTERN_C
-static DWORD w32_platform = (DWORD)-1;
+static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
#define ONE_K_BUFSIZE 1024
@@ -130,13 +133,13 @@ _matherr(struct _exception *a)
int
IsWin95(void)
{
- return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS);
+ return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
}
int
IsWinNT(void)
{
- return (win32_os_id() == VER_PLATFORM_WIN32_NT);
+ return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT);
}
EXTERN_C void
@@ -426,15 +429,7 @@ Perl_my_pclose(pTHX_ PerlIO *fp)
DllExport unsigned long
win32_os_id(void)
{
- static OSVERSIONINFO osver;
-
- if (osver.dwPlatformId != w32_platform) {
- memset(&osver, 0, sizeof(OSVERSIONINFO));
- osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&osver);
- w32_platform = osver.dwPlatformId;
- }
- return (unsigned long)w32_platform;
+ return (unsigned long)g_osver.dwPlatformId;
}
DllExport int
@@ -1038,6 +1033,8 @@ remove_dead_pseudo_process(long child)
(w32_num_pseudo_children-child-1), HANDLE);
Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
(w32_num_pseudo_children-child-1), DWORD);
+ Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
+ (w32_num_pseudo_children-child-1), HWND);
w32_num_pseudo_children--;
}
}
@@ -1055,11 +1052,13 @@ win32_kill(int pid, int sig)
/* it is a pseudo-forked child */
child = find_pseudo_pid(-pid);
if (child >= 0) {
+ HWND hwnd = w32_pseudo_child_message_hwnds[child];
hProcess = w32_pseudo_child_handles[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)) {
@@ -1067,16 +1066,30 @@ win32_kill(int pid, int sig)
return 0;
}
break;
- default:
- /* We fake signals to pseudo-processes using Win32
- * message queue. In Win9X the pids are negative already. */
- if (PostThreadMessage(IsWin95() ? pid : -pid,WM_USER,sig,0)) {
- /* It might be us ... */
- PERL_ASYNC_CHECK();
- return 0;
- }
+
+ default: {
+ int count = 0;
+ /* pseudo-process has not yet properly initialized if hwnd isn't set */
+ while (hwnd == INVALID_HANDLE_VALUE && count < 5) {
+ /* Yield and wait for the other thread to send us its message_hwnd */
+ Sleep(0);
+ win32_async_check(aTHX);
+ ++count;
+ }
+ if (hwnd != INVALID_HANDLE_VALUE) {
+ /* We fake signals to pseudo-processes using Win32
+ * message queue. In Win9X the pids are negative already. */
+ if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
+ PostThreadMessage(IsWin95() ? pid : -pid, WM_USER_KILL, sig, 0))
+ {
+ /* It might be us ... */
+ PERL_ASYNC_CHECK();
+ return 0;
+ }
+ }
break;
}
+ } /* switch */
}
else if (IsWin95()) {
pid = -pid;
@@ -1585,44 +1598,34 @@ win32_uname(struct utsname *name)
{
struct hostent *hep;
STRLEN nodemax = sizeof(name->nodename)-1;
- OSVERSIONINFO osver;
-
- memset(&osver, 0, sizeof(OSVERSIONINFO));
- osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (GetVersionEx(&osver)) {
- /* sysname */
- switch (osver.dwPlatformId) {
- case VER_PLATFORM_WIN32_WINDOWS:
- strcpy(name->sysname, "Windows");
- break;
- case VER_PLATFORM_WIN32_NT:
- strcpy(name->sysname, "Windows NT");
- break;
- case VER_PLATFORM_WIN32s:
- strcpy(name->sysname, "Win32s");
- break;
- default:
- strcpy(name->sysname, "Win32 Unknown");
- break;
- }
- /* release */
- sprintf(name->release, "%d.%d",
- osver.dwMajorVersion, osver.dwMinorVersion);
-
- /* version */
- sprintf(name->version, "Build %d",
- osver.dwPlatformId == VER_PLATFORM_WIN32_NT
- ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
- if (osver.szCSDVersion[0]) {
- char *buf = name->version + strlen(name->version);
- sprintf(buf, " (%s)", osver.szCSDVersion);
- }
+ /* sysname */
+ switch (g_osver.dwPlatformId) {
+ case VER_PLATFORM_WIN32_WINDOWS:
+ strcpy(name->sysname, "Windows");
+ break;
+ case VER_PLATFORM_WIN32_NT:
+ strcpy(name->sysname, "Windows NT");
+ break;
+ case VER_PLATFORM_WIN32s:
+ strcpy(name->sysname, "Win32s");
+ break;
+ default:
+ strcpy(name->sysname, "Win32 Unknown");
+ break;
}
- else {
- *name->sysname = '\0';
- *name->version = '\0';
- *name->release = '\0';
+
+ /* release */
+ sprintf(name->release, "%d.%d",
+ g_osver.dwMajorVersion, g_osver.dwMinorVersion);
+
+ /* version */
+ sprintf(name->version, "Build %d",
+ g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
+ ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
+ if (g_osver.szCSDVersion[0]) {
+ char *buf = name->version + strlen(name->version);
+ sprintf(buf, " (%s)", g_osver.szCSDVersion);
}
/* nodename */
@@ -1757,65 +1760,60 @@ DllExport int
win32_async_check(pTHX)
{
MSG msg;
- int ours = 1;
+ HWND hwnd = w32_message_hwnd;
+
+ w32_poll_count = 0;
+
+ if (hwnd == INVALID_HANDLE_VALUE)
+ return 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)) {
- int sig;
- switch(msg.message) {
+ if (hwnd == NULL)
+ hwnd = (HWND)-1;
-#if 0
- /* Perhaps some other messages could map to signals ? ... */
- case WM_CLOSE:
- case WM_QUIT:
- /* Treat WM_QUIT like SIGHUP? */
- sig = SIGHUP;
- goto Raise;
- break;
+ while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
+ PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
+ {
+ switch (msg.message) {
+#ifdef USE_ITHREADS
+ case WM_USER_MESSAGE: {
+ int child = find_pseudo_pid(msg.wParam);
+ if (child >= 0)
+ w32_pseudo_child_message_hwnds[child] = (HWND)msg.lParam;
+ break;
+ }
#endif
- /* We use WM_USER to fake kill() with other signals */
- case WM_USER: {
- sig = msg.wParam;
- Raise:
- if (do_raise(aTHX_ sig)) {
- sig_terminate(aTHX_ sig);
- }
+ case WM_USER_KILL: {
+ /* We use WM_USER to fake kill() with other signals */
+ int sig = msg.wParam;
+ if (do_raise(aTHX_ sig))
+ sig_terminate(aTHX_ sig);
break;
}
case WM_TIMER: {
/* alarm() is a one-shot but SetTimer() repeats so kill it */
if (w32_timerid && w32_timerid==msg.wParam) {
- KillTimer(NULL,w32_timerid);
+ KillTimer(w32_message_hwnd, w32_timerid);
w32_timerid=0;
- }
- else
- goto FallThrough;
- /* Now fake a call to signal handler */
- if (do_raise(aTHX_ 14)) {
- sig_terminate(aTHX_ 14);
- }
- break;
- }
- /* Otherwise do normal Win32 thing - in case it is useful */
- default:
- FallThrough:
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- ours = 0;
+ /* Now fake a call to signal handler */
+ if (do_raise(aTHX_ 14))
+ sig_terminate(aTHX_ 14);
+ }
break;
}
+ } /* switch */
}
- w32_poll_count = 0;
/* Above or other stuff may have set a signal flag */
if (PL_sig_pending) {
despatch_signals();
}
- return ours;
+ return 1;
}
/* This function will not return until the timeout has elapsed, or until
@@ -2028,13 +2026,22 @@ win32_alarm(unsigned int sec)
* one of the supported codes in <signal.h>
*/
dTHX;
+
+ if (w32_message_hwnd == INVALID_HANDLE_VALUE)
+ w32_message_hwnd = win32_create_message_window();
+
if (sec) {
- w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
+ if (w32_message_hwnd == NULL)
+ w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
+ else {
+ w32_timerid = 1;
+ SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
+ }
}
else {
if (w32_timerid) {
- KillTimer(NULL,w32_timerid);
- w32_timerid=0;
+ KillTimer(w32_message_hwnd, w32_timerid);
+ w32_timerid = 0;
}
}
return 0;
@@ -4881,10 +4888,33 @@ win32_csighandler(int sig)
/* Does nothing */
}
+HWND
+win32_create_message_window()
+{
+ /* "message-only" windows have been implemented in Windows 2000 and later.
+ * On earlier versions we'll continue to post messages to a specific
+ * thread and use hwnd==NULL. This is brittle when either an embedding
+ * application or an XS module is also posting messages to hwnd=NULL
+ * because once removed from the queue they cannot be delivered to the
+ * "right" place with DispatchMessage() anymore, as there is no WindowProc
+ * if there is no window handle.
+ */
+ if (g_osver.dwMajorVersion < 5)
+ return NULL;
+
+ return CreateWindow("Static", "", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL);
+}
+
void
Perl_sys_intern_init(pTHX)
{
int i;
+
+ if (g_osver.dwOSVersionInfoSize == 0) {
+ g_osver.dwOSVersionInfoSize = sizeof(g_osver);
+ GetVersionEx(&g_osver);
+ }
+
w32_perlshell_tokens = Nullch;
w32_perlshell_vec = (char**)NULL;
w32_perlshell_items = 0;
@@ -4893,10 +4923,11 @@ Perl_sys_intern_init(pTHX)
w32_num_children = 0;
# ifdef USE_ITHREADS
w32_pseudo_id = 0;
- Newx(w32_pseudo_children, 1, child_tab);
+ Newx(w32_pseudo_children, 1, pseudo_child_tab);
w32_num_pseudo_children = 0;
# endif
w32_timerid = 0;
+ w32_message_hwnd = INVALID_HANDLE_VALUE;
w32_poll_count = 0;
for (i=0; i < SIG_SIZE; i++) {
w32_sighandler[i] = SIG_DFL;
@@ -4922,9 +4953,11 @@ Perl_sys_intern_clear(pTHX)
/* NOTE: w32_fdpid is freed by sv_clean_all() */
Safefree(w32_children);
if (w32_timerid) {
- KillTimer(NULL,w32_timerid);
- w32_timerid=0;
+ KillTimer(w32_message_hwnd, w32_timerid);
+ w32_timerid = 0;
}
+ if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
+ DestroyWindow(w32_message_hwnd);
# ifdef MULTIPLICITY
if (my_perl == PL_curinterp) {
# else
@@ -4948,9 +4981,10 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
dst->fdpid = newAV();
Newxz(dst->children, 1, child_tab);
dst->pseudo_id = 0;
- Newxz(dst->pseudo_children, 1, child_tab);
- dst->timerid = 0;
- dst->poll_count = 0;
+ Newxz(dst->pseudo_children, 1, pseudo_child_tab);
+ dst->timerid = 0;
+ w32_message_hwnd = INVALID_HANDLE_VALUE;
+ dst->poll_count = 0;
Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
}
# endif /* USE_ITHREADS */
diff --git a/win32/win32.h b/win32/win32.h
index 8f5b27d01e..f318890a9b 100644
--- a/win32/win32.h
+++ b/win32/win32.h
@@ -304,6 +304,7 @@ typedef struct {
} child_IO_table;
DllExport void win32_get_child_IO(child_IO_table* ptr);
+DllExport HWND win32_create_message_window();
#ifndef USE_SOCKETS_AS_HANDLES
extern FILE * my_fdopen(int, char *);
@@ -353,6 +354,16 @@ typedef char * caddr_t; /* In malloc.c (core address). */
* Now Win32 specific per-thread data stuff
*/
+/* Leave the first couple ids after WM_USER unused because they
+ * might be used by an embedding application, and on Windows
+ * version before 2000 we might end up eating those messages
+ * if they were not meant for us.
+ */
+#define WM_USER_MIN (WM_USER+30)
+#define WM_USER_MESSAGE (WM_USER_MIN)
+#define WM_USER_KILL (WM_USER_MIN+1)
+#define WM_USER_MAX (WM_USER_MIN+1)
+
struct thread_intern {
/* XXX can probably use one buffer instead of several */
char Wstrerror_buffer[512];
@@ -375,6 +386,15 @@ typedef struct {
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
} child_tab;
+#ifdef USE_ITHREADS
+typedef struct {
+ long num;
+ DWORD pids[MAXIMUM_WAIT_OBJECTS];
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ HWND message_hwnds[MAXIMUM_WAIT_OBJECTS];
+} pseudo_child_tab;
+#endif
+
#ifndef Sighandler_t
typedef Signal_t (*Sighandler_t) (int);
#define Sighandler_t Sighandler_t
@@ -388,10 +408,11 @@ struct interp_intern {
child_tab * children;
#ifdef USE_ITHREADS
DWORD pseudo_id;
- child_tab * pseudo_children;
+ pseudo_child_tab * pseudo_children;
#endif
void * internal_host;
struct thread_intern thr_intern;
+ HWND message_hwnd;
UINT timerid;
unsigned poll_count;
Sighandler_t sigtable[SIG_SIZE];
@@ -415,8 +436,10 @@ DllExport int win32_async_check(pTHX);
#define w32_num_pseudo_children (w32_pseudo_children->num)
#define w32_pseudo_child_pids (w32_pseudo_children->pids)
#define w32_pseudo_child_handles (w32_pseudo_children->handles)
+#define w32_pseudo_child_message_hwnds (w32_pseudo_children->message_hwnds)
#define w32_internal_host (PL_sys_intern.internal_host)
#define w32_timerid (PL_sys_intern.timerid)
+#define w32_message_hwnd (PL_sys_intern.message_hwnd)
#define w32_sighandler (PL_sys_intern.sigtable)
#define w32_poll_count (PL_sys_intern.poll_count)
#define w32_do_async (w32_poll_count++ > WIN32_POLL_INTERVAL)