1 /*
2 This file is part of GNU APL, a free implementation of the
3 ISO/IEC Standard 13751, "Programming Language APL, Extended"
4
5 Copyright (C) 2008-2016 Dr. Jürgen Sauermann
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifndef __COMMON_HH_DEFINED__
22 #define __COMMON_HH_DEFINED__
23
24 #include "../config.h" // for xxx_WANTED and other macros from ./configure
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <sys/un.h>
28 #include <sys/stat.h>
29 #include <sys/fcntl.h>
30
31 #ifdef ENABLE_NLS
32 #include <libintl.h>
33 #endif
34
35 #ifndef MAX_RANK_WANTED
36 #define MAX_RANK_WANTED 6
37 #endif
38
39 enum { MAX_RANK = MAX_RANK_WANTED };
40
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <sys/resource.h>
45 #include <sys/time.h>
46
47 #ifndef RLIM_INFINITY // Raspberry
48 #define RLIM_INFINITY (~rlim_t(0))
49 #endif
50
51 // if someone (like curses on Solaris) has #defined erase() then
52 // #undef it because vector would not be happy with it
53 #ifdef erase
54 #undef erase
55 #endif
56
57 #include <complex>
58 #include <iostream>
59 #include <iomanip>
60 #include <fstream>
61
62 #include "APL_types.hh"
63 #include "Assert.hh"
64 #include "Logging.hh"
65 #include "SystemLimits.hh"
66
67 using namespace std;
68
69 /// true when a WINCH (window size changed) signal was received
70 extern bool got_WINCH;
71
72 /// initialize
73 extern void init_1(const char * argv0, bool log_startup);
74 extern void init_2(bool log_startup);
75
76 /// clean up
77 extern void cleanup(bool soft);
78
79 /// true if Control-C was hit (once)
80 extern bool attention_is_raised();
81
82 /// set the attention_raised flag
83 extern void set_attention_raised(const char * loc);
84
85 /// clear the attention_raised flag
86 extern void clear_attention_raised(const char * loc);
87
88 /// true if Control-C was hit twice within 500 ms
89 extern bool interrupt_is_raised();
90
91 /// set the interrupt_raised flag
92 extern void set_interrupt_raised(const char * loc);
93
94 /// clear the interrupt_raised flag
95 extern void clear_interrupt_raised(const char * loc);
96
97 /// the number of Control-C signals received
98 extern uint64_t interrupt_count;
99
100 /// time when ^C was hit last
101 extern APL_time_us interrupt_when;
102
103 /// signal handler for ^C
104 extern void control_C(int);
105
106 /// normal APL output (to stdout)
107 extern ostream COUT;
108
109 /// debug output (to stderrear_interrupt_raised
110 extern ostream CERR;
111
112 /// debug output (to stderr)
113 extern ostream UERR;
114
115 class UCS_string;
116 extern UCS_string & MORE_ERROR();
117
118 #define loop(v, e) for (ShapeItem v = 0; v < ShapeItem(e); ++v)
119
120 // #define TROUBLESHOOT_NEW_DELETE
121
122 void * common_new(size_t size);
123 void common_delete(void * p);
124
125 /// current time as microseconds since epoch
126 APL_time_us now();
127
128 /// CPU cycle counter (if present)
129 #if HAVE_RDTSC
cycle_counter()130 inline uint64_t cycle_counter()
131 {
132 uint32_t lo, hi;
133 __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
134 return uint64_t(hi) << 32 | lo;
135 }
136
137 #else // not HAVE_RDTSC
138
cycle_counter()139 inline uint64_t cycle_counter()
140 {
141 timeval tv;
142 gettimeofday(&tv, 0);
143 return tv.tv_sec * 1000000ULL + tv.tv_usec;
144 }
145 #endif // HAVE_RDTSC
146
147 //-----------------------------------------------------------------------------
148 #if HAVE_SEM_INIT
149
150 # define __sem_destroy(sem) sem_destroy(sem)
151 # define __sem_init(sem, pshared, value) sem_init(sem, pshared, value)
152
153 #else // not HAVE_SEM_INIT
154
155 # define __sem_destroy(sem) { if (sem) sem_close(sem); }
156 # define __sem_init(sem, _pshared, value) \
157 { \
158 char sname[100]; \
159 { /* create a unique name */ \
160 timeval tv; gettimeofday(&tv, 0); \
161 unsigned int secs = tv.tv_sec, usecs = tv.tv_usec; \
162 snprintf(sname, sizeof(sname), "/gnu_apl_%s_%u_%u", \
163 #sem, secs, usecs); \
164 } \
165 enum { mode = S_IRWXU | S_IRWXG | S_IRWXO }; \
166 sem = sem_open(sname, O_CREAT, mode, value); \
167 }
168 #endif // HAVE_SEM_INIT
169 //-----------------------------------------------------------------------------
170 /**
171 Software probes. A probe is a measurement of CPU cycles executed between two
172 points P1 and P2 in the source code.
173 */
174 /// CPU cycle counter for performance measurements
175 class Probe
176 {
177 public:
178 /// some Proble related parameters
179 enum { PROBE_COUNT = 100, ///< the number of probes
180 PROBE_LEN = 20 ///< the number of measurements in each probe
181 };
182
183 /// constructor
Probe()184 Probe()
185 { init(); }
186
187 /// initialize this probe
init()188 void init()
189 {
190 idx = 0;
191 start_p = &dummy;
192 stop_p = &dummy;
193 }
194
195 /// init the p'th probe
init(int p)196 static int init(int p)
197 { if (p >= PROBE_COUNT) return -3;
198 probes[p].init();
199 return 0;
200 }
201
202 /// initialize all probes
init_all()203 static void init_all()
204 { loop(p, PROBE_COUNT) init(p); }
205
206 /// start time measurement
start()207 void start()
208 {
209 if (idx < PROBE_LEN)
210 {
211 measurement & m = measurements[idx];
212 start_p = &m.cycles_from;
213 stop_p = &m.cycles_to;
214 }
215 else
216 {
217 start_p = &dummy;
218 stop_p = &dummy;
219 }
220
221 // write to *start_p and *stop_p so that they are loaded into the cache
222 //
223 *stop_p = cycle_counter();
224 *start_p = cycle_counter();
225
226 // now the real start of the measurment
227 //
228 *start_p = cycle_counter();
229 }
230
231 /// stop time measurement
stop()232 void stop()
233 {
234 // the real end of the measurment
235 //
236 *stop_p = cycle_counter();
237 ++idx;
238 }
239
240 /// get the m'th time (from P1 to P2) of this probe
get_time(int m) const241 int64_t get_time(int m) const
242 { if (m >= idx) return -1;
243 const int64_t diff = measurements[m].cycles_to
244 - measurements[m].cycles_from;
245 if (diff < 0) return -2;
246 return diff;
247 }
248
249 /// get the m'th time of the p'th probe
get_time(int p,int m)250 static int get_time(int p, int m)
251 { if (p >= PROBE_COUNT) return -3;
252 return probes[p].get_time(m);
253 }
254
255 /// get the m'th start time of this probe
get_start(int m) const256 int64_t get_start(int m) const
257 { if (m >= idx) return -1;
258 return measurements[m].cycles_from;
259 }
260
261 /// get the m'th start time of the p'th probe
get_start(int p,int m)262 static int get_start(int p, int m)
263 { if (p >= PROBE_COUNT) return -3;
264 return probes[p].get_start(m);
265 }
266
267 /// get the m'th stop time of this probe
get_stop(int m) const268 int64_t get_stop(int m) const
269 { if (m >= idx) return -1;
270 return measurements[m].cycles_to;
271 }
272
273 /// get the m'th stop time of the p'th probe
get_stop(int p,int m)274 static int get_stop(int p, int m)
275 { if (p >= PROBE_COUNT) return -3;
276 return probes[p].get_stop(m);
277 }
278
279 /// get the number of times int the p'th probe
get_length(int p)280 static int get_length(int p)
281 { if (p >= PROBE_COUNT) return -3;
282 return probes[p].idx;
283 }
284
285 static Probe & P0; ///< start of vector probes
286 static Probe & P_1; ///< individual probe 1
287 static Probe & P_2; ///< individual probe 2
288 static Probe & P_3; ///< individual probe 3
289 static Probe & P_4; ///< individual probe 4
290 static Probe & P_5; ///< individual probe 5
291
292 protected:
293 /// one time measurement, measuring cCPU cycles spent between
294 /// ttw points in the source code
295 struct measurement
296 {
297 int64_t cycles_from; ///< the cycle counter at point 1
298 int64_t cycles_to; ///< the cycle counter at point 2
299 };
300
301 /// all measurements
302 measurement measurements[PROBE_LEN];
303
304 /// index into \b probes
305 int idx;
306
307 /// start time
308 int64_t * start_p;
309
310 /// end time
311 int64_t * stop_p;
312
313 /// a dummy used when \b idx exceeds \b probes
314 static int64_t dummy;
315
316 /// all probes
317 static Probe probes[];
318 };
319 //-----------------------------------------------------------------------------
320 /// Year, Month, Day, hour, minute, second, millisecond
321 struct YMDhmsu
322 {
323 /// construct YMDhmsu from usec since Jan. 1. 1970 00:00:00
324 YMDhmsu(APL_time_us t);
325
326 /// return usec since Jan. 1. 1970 00:00:00
327 APL_time_us get() const;
328
329 int year; ///< year, e.g. 2013
330 int month; ///< month 1-12
331 int day; ///< day 1-31
332 int hour; ///< hour 0-23
333 int minute; ///< minute 0-59
334 int second; ///< second 0-59
335 int micro; ///< microseconds 0-999999
336 };
337 //-----------------------------------------------------------------------------
338 /// whether ⎕LX shall be executed at the end of the file
339 enum LX_mode
340 {
341 no_LX = 0, ///< no
342 do_LX = 1 ///< yes
343 };
344 //-----------------------------------------------------------------------------
345
346 #ifdef TROUBLESHOOT_NEW_DELETE
operator new(size_t size)347 inline void * operator new(size_t size) { return common_new(size); }
operator delete(void * p)348 inline void operator delete(void * p) { common_delete(p); }
349 #endif
350
351 using namespace std;
352
353 //-----------------------------------------------------------------------------
354
355 /// return true iff \b uni is a padding character (used internally).
is_iPAD_char(Unicode uni)356 inline bool is_iPAD_char(Unicode uni)
357 { return ((uni >= UNI_iPAD_U2) && (uni <= UNI_iPAD_U1)) ||
358 ((uni >= UNI_iPAD_U0) && (uni <= UNI_iPAD_L9)); }
359
360 //-----------------------------------------------------------------------------
361
362 /// Stringify x.
363 #define STR(x) #x
364 /// The current location in the source file.
365 #define LOC Loc(__FILE__, __LINE__)
366 /// The location line l in file f.
367 #define Loc(f, l) f ":" STR(l)
368
369 extern ostream & get_CERR();
370
371 /// print something and the source code location
372 #define Q(x) get_CERR() << std::left << setw(20) << #x ":" << " '" << x << "' at " LOC << endl;
373
374 /// same as Q1 (for printouts guarded by Log macros). Unlike Q() which should
375 /// NOT remain in the code Q1 should remain in the code.
376 #define Q1(x) get_CERR() << std::left << setw(20) << #x ":" << " '" << x << "' at " LOC << endl;
377
378 //-----------------------------------------------------------------------------
379
380 #ifdef VALUE_HISTORY_WANTED
381
382 enum { VALUEHISTORY_SIZE = 100000 };
383 extern void add_event(const Value * val, VH_event ev, int ia,
384 const char * loc);
385 # define ADD_EVENT(val, ev, ia, loc) add_event(val, ev, ia, loc);
386
387 #else
388
389 enum { VALUEHISTORY_SIZE = 0 };
390 # define ADD_EVENT(_val, _ev, _ia, _loc)
391
392 #endif
393
394 //=============================================================================
395 /// Function_Line ++ (post increment)
operator ++(Function_Line & fl,int)396 inline int operator ++(Function_Line & fl, int)
397 {
398 Function_Line ret = fl;
399 fl = Function_Line(fl + 1);
400 return ret;
401 }
402 //=============================================================================
skip_spaces(const char * & p)403 inline void skip_spaces(const char * & p)
404 {
405 while (*p && *p <= ' ') ++p;
406 }
407 //=============================================================================
408 inline Function_PC
operator +(Function_PC pc,int offset)409 operator +(Function_PC pc, int offset)
410 {
411 return Function_PC(int(pc) + offset);
412 }
413 //-----------------------------------------------------------------------------
414 inline Function_PC
operator -(Function_PC pc,int offset)415 operator -(Function_PC pc, int offset)
416 {
417 return Function_PC(int(pc) - offset);
418 }
419 //-----------------------------------------------------------------------------
420 /// Function_PC ++ (post increment)
421 inline Function_PC
operator ++(Function_PC & pc,int)422 operator ++(Function_PC & pc, int)
423 {
424 const Function_PC before = pc;
425 pc = pc + 1;
426 return before;
427 }
428 //-----------------------------------------------------------------------------
429 /// Function_PC ++ (pre increment)
430 inline Function_PC &
operator ++(Function_PC & pc)431 operator ++(Function_PC & pc)
432 {
433 pc = pc + 1;
434 return pc;
435 }
436 //-----------------------------------------------------------------------------
437 /// Function_PC -- (pre decrement)
438 inline Function_PC &
operator --(Function_PC & pc)439 operator --(Function_PC & pc)
440 {
441 pc = pc - 1;
442 return pc;
443 }
444 //-----------------------------------------------------------------------------
445 /// frequently used cast to const char *
446 inline const char *
charP(const void * vp)447 charP(const void * vp)
448 {
449 return reinterpret_cast<const char *>(vp);
450 }
451 //-----------------------------------------------------------------------------
452
453 #define uhex std::hex << uppercase << setfill('0')
454 #define lhex std::hex << nouppercase << setfill('0')
455 #define nohex std::dec << nouppercase << setfill(' ')
456
457 /// formatting for hex (and similar) values
458 #define HEX(x) "0x" << uhex << int64_t(x) << nohex
459 #define HEX2(x) "0x" << uhex << std::right << \
460 setw(2) << int(x) << std::left << nohex
461 #define HEX4(x) "0x" << uhex << std::right << \
462 setw(4) << int(x) << std::left << nohex
463 #define UNI(x) "U+" << uhex << setw(4) << int(x) << nohex
464
465 /// cast to a const void *
voidP(const void * addr)466 inline const void * voidP(const void * addr) { return addr; }
467
468 //-----------------------------------------------------------------------------
469 /// A union holding a sockaddr and a sockaddr_in as to avoid casting
470 /// between sockaddr and a sockaddr_in
471 union SockAddr
472 {
473 /// an arbitrary socket address
474 sockaddr addr;
475
476 /// an AF_INET socket address
477 sockaddr_in inet;
478
479 /// an AF_UNIX socket address
480 sockaddr_un uNix;
481 };
482 //-----------------------------------------------------------------------------
483
484 #endif // __COMMON_HH_DEFINED__
485