DllExport unsigned int win32_alarm(unsigned int sec) { /* * 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 */ dTHX; if (w32_message_hwnd == INVALID_HANDLE_VALUE) w32_message_hwnd = win32_create_message_window(); if (sec) { 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(w32_message_hwnd, w32_timerid); w32_timerid = 0; } } return 0; } #### static LRESULT win32_process_message(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { /* BEWARE. The context retrieved using dTHX; is the context of the * 'parent' thread during the CreateWindow() phase - i.e. for all messages * up to and including WM_CREATE. If it ever happens that you need the * 'child' context before this, then it needs to be passed into * win32_create_message_window(), and passed to the WM_NCCREATE handler * from the lparam of CreateWindow(). It could then be stored/retrieved * using [GS]etWindowLongPtr(... GWLP_USERDATA ...), possibly eliminating * the dTHX calls here. */ /* XXX For now it is assumed that the overhead of the dTHX; for what * are relativley infrequent code-paths, is better than the added * complexity of getting the correct context passed into * win32_create_message_window() */ dTHX; switch(msg) { #ifdef USE_ITHREADS case WM_USER_MESSAGE: { long child = find_pseudo_pid(aTHX_ (int)wParam); if (child >= 0) { w32_pseudo_child_message_hwnds[child] = (HWND)lParam; return 1; } break; } #endif case WM_USER_KILL: { /* We use WM_USER_KILL to fake kill() with other signals */ int sig = (int)wParam; if (do_raise(aTHX_ sig)) sig_terminate(aTHX_ sig); return 1; } case WM_TIMER: { /* alarm() is a one-shot but SetTimer() repeats so kill it */ if (w32_timerid && w32_timerid==(UINT)wParam) { KillTimer(w32_message_hwnd, w32_timerid); w32_timerid=0; /* Now fake a call to signal handler */ if (do_raise(aTHX_ 14)) sig_terminate(aTHX_ 14); return 1; } break; } default: break; } /* switch */ /* Above or other stuff may have set a signal flag, and we may not have * been called from win32_async_check() (e.g. some other GUI's message * loop. BUT DON'T dispatch signals here: If someone has set a SIGALRM * handler that die's, and the message loop that calls here is wrapped * in an eval, then you may well end up with orphaned windows - signals * are dispatched by win32_async_check() */ return 0; } #### >perl lockdemo.pl locker: flock LOCK_EX locker: locked locker: sleep 10 main: alarm 5 main: flock LOCK_EX ### The lock is acquired here main: timeout at lockdemo.pl line 30. ### before the timeout occurs. main: 5 seconds have passed locker: flock LOCK_UN locker: unlocked