Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * @f alarm
15 : * @a M.L. Kersten, P. Boncz
16 : *
17 : * @+ Timers and Timed Interrupts
18 : * This module handles various signaling/timer functionalities.
19 : * The Monet interface supports two timer commands: @emph{ alarm} and @emph{ sleep}.
20 : * Their argument is the number of seconds to wait before the timer goes off.
21 : * The @emph{ sleep} command blocks till the alarm goes off.
22 : * The @emph{ alarm} command continues directly, executes off a
23 : * string when it goes off.
24 : * The parameterless routines @emph{ time} and @emph{ ctime} provide access to
25 : * the cpu clock.They return an integer and string, respectively.
26 : */
27 : #include "monetdb_config.h"
28 : #include "mal.h"
29 : #include "mal_client.h"
30 : #include "mal_interpreter.h"
31 : #include <time.h>
32 : #include "mal_exception.h"
33 :
34 : static str
35 30 : ALARMusec(lng *ret)
36 : {
37 30 : *ret = GDKusec();
38 30 : return MAL_SUCCEED;
39 : }
40 :
41 : #define SLEEP_SINGLE(TPE) \
42 : do { \
43 : TPE *res = (TPE*) getArgReference(stk, pci, 0), *msecs = (TPE*) getArgReference(stk,pci,1); \
44 : if (is_##TPE##_nil(*msecs)) \
45 : throw(MAL, "alarm.sleep", "NULL values not allowed for sleeping time"); \
46 : if (*msecs < 0) \
47 : throw(MAL, "alarm.sleep", "Cannot sleep for a negative time"); \
48 : MT_sleep_ms((unsigned int) *msecs); \
49 : *res = *msecs; \
50 : } while (0)
51 :
52 : #define SLEEP_MULTI(TPE) \
53 : do { \
54 : for (i = 0; i < j ; i++) { \
55 : if (is_##TPE##_nil(bb[i])) { \
56 : bat_iterator_end(&bi); \
57 : BBPreclaim(r); \
58 : BBPunfix(b->batCacheid); \
59 : throw(MAL, "alarm.sleep", "NULL values not allowed for sleeping time"); \
60 : } \
61 : if (bb[i] < 0) { \
62 : bat_iterator_end(&bi); \
63 : BBPreclaim(r); \
64 : BBPunfix(b->batCacheid); \
65 : throw(MAL, "alarm.sleep", "Cannot sleep for a negative time"); \
66 : } \
67 : } \
68 : for (i = 0; i < j ; i++) { \
69 : MT_sleep_ms((unsigned int) bb[i]); \
70 : rb[i] = bb[i]; \
71 : } \
72 : } while (0)
73 :
74 : static str
75 10 : ALARMsleep(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
76 : {
77 10 : BAT *r = NULL, *b = NULL;
78 10 : int *restrict rb, *restrict bb, tpe;
79 10 : BUN i, j;
80 :
81 10 : (void) cntxt;
82 10 : if (getArgType(mb, pci, 0) != TYPE_void
83 10 : && isaBatType(getArgType(mb, pci, 1))) {
84 0 : bat *res = getArgReference_bat(stk, pci, 0);
85 0 : bat *bid = getArgReference_bat(stk, pci, 1);
86 0 : tpe = getArgType(mb, pci, 1);
87 :
88 0 : if (!(b = BATdescriptor(*bid)))
89 0 : throw(MAL, "alarm.sleep",
90 : SQLSTATE(HY005) "Cannot access column descriptor");
91 :
92 0 : BATiter bi = bat_iterator(b);
93 0 : j = bi.count;
94 0 : bb = bi.base;
95 :
96 0 : if (!(r = COLnew(0, tpe, j, TRANSIENT))) {
97 0 : bat_iterator_end(&bi);
98 0 : BBPunfix(b->batCacheid);
99 0 : throw(MAL, "alarm.sleep", SQLSTATE(HY013) MAL_MALLOC_FAIL);
100 : }
101 0 : rb = Tloc(r, 0);
102 :
103 0 : switch (tpe) {
104 : case TYPE_bte:
105 : SLEEP_MULTI(bte);
106 : break;
107 : case TYPE_sht:
108 : SLEEP_MULTI(sht);
109 : break;
110 : case TYPE_int:
111 : SLEEP_MULTI(int);
112 : break;
113 : default:{
114 0 : bat_iterator_end(&bi);
115 0 : BBPreclaim(r);
116 0 : BBPunfix(b->batCacheid);
117 0 : throw(MAL, "alarm.sleep",
118 : SQLSTATE(42000) "Sleep function not available for type %s",
119 : ATOMname(tpe));
120 : }
121 : }
122 : bat_iterator_end(&bi);
123 :
124 : BBPunfix(b->batCacheid);
125 : *res = r->batCacheid;
126 : BBPkeepref(r);
127 : } else {
128 10 : switch (getArgType(mb, pci, 1)) {
129 0 : case TYPE_bte:
130 0 : SLEEP_SINGLE(bte);
131 0 : break;
132 0 : case TYPE_sht:
133 0 : SLEEP_SINGLE(sht);
134 0 : break;
135 10 : case TYPE_int:
136 10 : SLEEP_SINGLE(int);
137 10 : break;
138 0 : default:
139 0 : throw(MAL, "alarm.sleep",
140 : SQLSTATE(42000) "Sleep function not available for type %s",
141 : ATOMname(getArgType(mb, pci, 1)));
142 : }
143 : }
144 : return MAL_SUCCEED;
145 : }
146 :
147 : static str
148 0 : ALARMctime(str *res)
149 : {
150 0 : time_t t = time(0);
151 0 : char *base;
152 0 : char buf[26];
153 :
154 : #ifdef HAVE_CTIME_R3
155 : base = ctime_r(&t, buf, sizeof(buf));
156 : #else
157 0 : base = ctime_r(&t, buf);
158 : #endif
159 0 : if (base == NULL)
160 : /* very unlikely to happen... */
161 0 : throw(MAL, "alarm.ctime", "failed to format time");
162 :
163 0 : base[24] = 0; /* squash final newline */
164 0 : *res = GDKstrdup(base);
165 0 : if (*res == NULL)
166 0 : throw(MAL, "alarm.ctime", SQLSTATE(HY013) MAL_MALLOC_FAIL);
167 : return MAL_SUCCEED;
168 : }
169 :
170 : static str
171 0 : ALARMepoch(int *res)
172 : { /* XXX should be lng */
173 0 : *res = (int) time(0);
174 0 : return MAL_SUCCEED;
175 : }
176 :
177 : static str
178 0 : ALARMtime(int *res)
179 : {
180 0 : *res = GDKms();
181 0 : return MAL_SUCCEED;
182 : }
183 :
184 : #include "mel.h"
185 : mel_func alarm_init_funcs[] = {
186 : pattern("alarm", "sleep", ALARMsleep, true, "Sleep a few milliseconds", args(1,2, arg("",void),argany("msecs",1))),
187 : pattern("alarm", "sleep", ALARMsleep, true, "Sleep a few milliseconds and return the slept value", args(1,2, argany("",1),argany("msecs",1))),
188 : pattern("alarm", "sleep", ALARMsleep, true, "Sleep a few milliseconds and return the slept value", args(1,2, batargany("",1),batargany("msecs",1))),
189 : command("alarm", "usec", ALARMusec, true, "Return time since Jan 1, 1970 in microseconds.", args(1,1, arg("",lng))),
190 : command("alarm", "time", ALARMtime, true, "Return time since program start in milliseconds.", args(1,1, arg("",int))),
191 : command("alarm", "epoch", ALARMepoch, true, "Return time since Jan 1, 1970 in seconds.", args(1,1, arg("",int))),
192 : command("alarm", "ctime", ALARMctime, true, "Return the current time as a C-time string.", args(1,1, arg("",str))),
193 : { .imp=NULL }
194 : };
195 : #include "mal_import.h"
196 : #ifdef _MSC_VER
197 : #undef read
198 : #pragma section(".CRT$XCU",read)
199 : #endif
200 329 : LIB_STARTUP_FUNC(init_alarm_mal)
201 329 : { mal_module("alarm", NULL, alarm_init_funcs); }
|