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