📄 alarm.mx
字号:
@' The contents of this file are subject to the MonetDB Public License@' Version 1.1 (the "License"); you may not use this file except in@' compliance with the License. You may obtain a copy of the License at@' http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html@'@' Software distributed under the License is distributed on an "AS IS"@' basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the@' License for the specific language governing rights and limitations@' under the License.@'@' The Original Code is the MonetDB Database System.@'@' The Initial Developer of the Original Code is CWI.@' Portions created by CWI are Copyright (C) 1997-2007 CWI.@' All Rights Reserved.@f alarm@a M.L. Kersten, P. Boncz@+ Timers and Timed InterruptsThis module handles various signaling/timer functionalities.The Monet interface supports two timer commands: @emph{ alarm} and @emph{ sleep}.Their argument is the number of seconds to wait before the timer goes off.The @emph{ sleep} command blocks till the alarm goes off.The @emph{ alarm} command continues directly, executes off a MILstring when it goes off.The parameterless routines @emph{ time} and @emph{ ctime} provide access tothe cpu clock.They return an integer and string, respectively.@{@malmodule alarm;command sleep(secs:int):void address ALARMsleep comment "sleep X secs";command alarm(secs:int, action:str):void address ALARMsetalarm comment "execute action in X secs";command timers() :bat[:str,:str] address ALARMtimerscomment "give a list of all active timers";command usec() :lng address ALARMuseccomment "return cpu microseconds info";command time() :int address ALARMtime comment "time in millisecs";command epoch() :int address ALARMepoch comment "current time as unix epoch";command ctime() :str address ALARMctime comment "current time as a string";command prelude():voidaddress ALARMprelude comment "Initialize alarm module";command epilogue():voidaddress ALARMepilogue comment "Finalize alarm module";alarm.prelude();@* Implementation@+ The Clock Interrupt GeneratorA clock event generator, called @%timer@, has been added to the database kernel.It accepts a message @%CLKalarm(sec, usec)@, which generates an alarmafter the time indicated.The timer maintains a small stack of timing events sorted in priority of firing.The top contains the next timer event to go off.The timer is disabled when no timer events are outstanding.@h#include <mal.h>#include <signal.h>#define MAXtimer 200typedef struct { str action; /* MIL action (as a string) */ MT_Sema sema; /* barrier */ time_t alarm_time; /* time when the alarm goes off */} monet_timer_t;@c#include "mal_config.h"#include "alarm.h"#include <time.h>#ifdef WIN32#ifndef LIBALARM#define alarm_export extern __declspec(dllimport)#else#define alarm_export extern __declspec(dllexport)#endif#else#define alarm_export extern#endifalarm_export str ALARMprelude(void);alarm_export str ALARMepilogue(void);alarm_export str ALARMusec(lng *ret);alarm_export str ALARMsleep(int *res, int *secs);alarm_export str ALARMsetalarm(int *res, int *secs, str *action);alarm_export str ALARMtimers(int *res);alarm_export str ALARMctime(str *res);alarm_export str ALARMepoch(int *res);alarm_export str ALARMtime(int *res);static monet_timer_t timer[MAXtimer];static int timerTop = 0;@@-The timer is awakened by a clock interrupt. The interrupt granularityis OS-dependent. The timer should be initialized as long as thereare outstanding timer events.@c#ifdef SIGALRMvoidCLKinitTimer(int sec, int usec){ int i = sec - time(0); (void) usec; TRGDEBUG THRprintf(GDKout, "#CLKinitTimer: set timer to %d secs \n", i); alarm(i);}#endif@-A new alarm is pushed onto the stack using @%CLKalarm@.The parameter is the real-time value to be approximated.@c#ifdef SIGALRMvoidCLKalarm(time_t t, str action){ int j; int k; TRGDEBUG THRprintf(GDKout, "#CLKalarm: push " LLFMT "\n", (lng) t); if (timerTop == MAXtimer) { GDKerror("CLKalarm: timer stack overflow\n"); return; } for (j = 0; j < timerTop; j++) { if (timer[j].alarm_time > t) break; } for (k = timerTop; k > j; k--) { timer[k] = timer[k - 1]; } timer[k].alarm_time = t; if (action) { timer[k].action = GDKstrdup(action); } else { timer[k].action = 0; MT_init_sema(timer[k].sema, 0); } if (k == timerTop++) { CLKinitTimer(t, 0); /* set it sooner */ }}#endif@-Once a timer interrupt occurs, we should inspect the timer queue andemit a notify signal.@c#ifdef SIGALRM/* HACK to pacify compiler */#if (defined(__INTEL_COMPILER) && (SIZEOF_VOID_P > SIZEOF_INT))#undef SIG_ERR /*((__sighandler_t)-1 ) */#define SIG_ERR ((__sighandler_t)-1L)#endifstatic RETSIGTYPECLKsignal(int nr){ /* int restype; */ int k = timerTop; int t; (void) nr; if (signal(SIGALRM, CLKsignal) == SIG_ERR) { GDKsyserror("CLKsignal: call failed\n"); } TRGDEBUG THRprintf(GDKout, "#alarm signal (timeTop=%d)\n", timerTop); if (timerTop == 0) { return; } t = time(0); while (k-- && t >= timer[k].alarm_time) { if (timer[k].action) { TRGDEBUG THRprintf(GDKout, "#eval(%s)\n", timer[k].action); /* monet_eval(timer[k].action, &restype); */ GDKfree(timer[k].action); } else { MT_up_sema(timer[k].sema, "CLKsignal"); } timerTop--; } if (timerTop > 0) { CLKinitTimer(timer[timerTop - 1].alarm_time, 0); }}#endifbat *CLKprelude(void){#ifdef SIGALRM (void) signal(SIGALRM, CLKsignal);#endif return NULL;}voidCLKepilogue(void){ int k;#if (defined(SIGALRM) && defined(SIG_IGN))/* HACK to pacify compiler */#if (defined(__INTEL_COMPILER) && (SIZEOF_VOID_P > SIZEOF_INT))#undef SIG_IGN /*((__sighandler_t)1 ) */#define SIG_IGN ((__sighandler_t)1L)#endif (void) signal(SIGALRM, SIG_IGN);#endif for (k = 0; k < timerTop; k++) { if (timer[k].action) GDKfree(timer[k].action); }}intCMDsleep(int *secs){ if (*secs < 0) { GDKerror("CMDsleep: negative delay\n"); return GDK_FAIL; } else {#ifdef __CYGWIN__ /* CYGWIN cannot handle SIGALRM with sleep */ lng t = GDKusec() + (*secs)*1000000; while (GDKusec() < t) ;#else MT_sleep_ms(*secs * 1000);#endif } return GDK_SUCCEED;}intCMDalarm(int *secs, str action){ if (*secs < 0) { GDKerror("CMDalarm: negative delay\n"); return GDK_FAIL; } else {#ifndef SIGALRM (void)action; GDKerror("CMDalarm: not implemented\n"); return GDK_FAIL;#else CLKalarm(time(0) + *secs, action);#endif } return GDK_SUCCEED;}@-Problem with CMDtimers is that they use static buffers thatmay be overwritten under parallel processing.Therefore, the code below is dangerous (!) and the re-entrant codeshould be used. However, on Windows where ctime_r is not available,ctime is actually thread-safe.@cintCMDtimers(BAT **retval){ char buf[27]; int k; *retval = BATnew(TYPE_str, TYPE_str, timerTop); if (*retval == NULL) return GDK_FAIL; BATroles(*retval, "alarm", "action"); for (k = 0; k < timerTop; k++) { time_t t = timer[k].alarm_time;#ifdef HAVE_CTIME_R3 ctime_r(&t, buf, sizeof(buf));#else#ifdef HAVE_CTIME_R ctime_r(&t, buf);#else strncpy(buf, ctime(&t), sizeof(buf));#endif#endif BUNins(*retval, buf, timer[k].action ? timer[k].action : "barrier", FALSE); } return GDK_SUCCEED;}intCMDctime(str *retval){ time_t t = time(0);#ifdef HAVE_CTIME_R3 char buf[26]; *retval = GDKstrdup(ctime_r(&t, buf, sizeof(buf)));#else#ifdef HAVE_CTIME_R char buf[26]; *retval = GDKstrdup(ctime_r(&t, buf));#else *retval = GDKstrdup(ctime(&t));#endif#endif return GDK_SUCCEED;}intCMDepoch(int *retval) /* XXX should be lng */{ *retval = (int) time(0); return GDK_SUCCEED;}/* should return lng */intCMDusec(lng *retval){ *retval = GDKusec(); return GDK_SUCCEED;}intCMDtime(int *retval){ *retval = GDKms(); return GDK_SUCCEED;}@- WrappingWrapping the Version 4 code base@c#include "mal.h"#include "mal_exception.h"voidALARMinitTimer(int sec, int usec){ (void) sec; (void) usec;#ifdef SIGALRM CLKinitTimer(sec, usec);#endif}#ifdef SIGALRMstrALARMalarm(int t, str *action){ CLKalarm(t, *action); return MAL_SUCCEED;}#endifstrALARMprelude(){#ifdef SIGALRM (void) signal(SIGALRM, (void (*)()) CLKsignal);#endif return MAL_SUCCEED;}strALARMepilogue(){ CLKepilogue(); return MAL_SUCCEED;}strALARMusec(lng *ret){ CMDusec(ret); return MAL_SUCCEED;}strALARMsleep(int *res, int *secs){ (void) res; /* fool compilers */ CMDsleep(secs); return MAL_SUCCEED;}strALARMsetalarm(int *res, int *secs, str *action){ (void) res; (void) secs; (void) action; /* foolc compiler */ throw(MAL, "alarm.setalarm", "Not yet implemented");}strALARMtimers(int *res){ (void) res; /* fool compiler */ throw(MAL, "alarm.timers", "Not yet implemented");}strALARMctime(str *res){ CMDctime(res); return MAL_SUCCEED;}strALARMepoch(int *res){ CMDepoch(res); return MAL_SUCCEED;}strALARMtime(int *res){ CMDtime(res); return MAL_SUCCEED;}@}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -