1 /****************************************************************************
2 **
3 **  This file is part of GAP, a system for computational discrete algebra.
4 **
5 **  Copyright of GAP belongs to its developers, whose names are too numerous
6 **  to list here. Please refer to the COPYRIGHT file for details.
7 **
8 **  SPDX-License-Identifier: GPL-2.0-or-later
9 **
10 **  The  file 'system.c'  declares  all operating system  dependent functions
11 **  except file/stream handling which is done in "sysfiles.h".
12 */
13 
14 #ifndef GAP_SYSTEM_H
15 #define GAP_SYSTEM_H
16 
17 /****************************************************************************
18 **
19 *V  autoconf  . . . . . . . . . . . . . . . . . . . . . . . .  use "config.h"
20 */
21 #include "config.h"
22 
23 #include <assert.h>
24 #include <ctype.h>
25 #include <limits.h>
26 #include <setjmp.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "debug.h"
33 
34 
35 /* check if we are on a 64 bit machine                                     */
36 #if SIZEOF_VOID_P == 8
37 # define SYS_IS_64_BIT          1
38 #elif !defined(SIZEOF_VOID_P)
39 # error Something is wrong with this GAP installation: SIZEOF_VOID_P not defined
40 #endif
41 
42 // check that the pointer size detected by configure matches that of the
43 // current compiler; this helps prevent kernel extensions from being
44 // compiled with the wrong ABI
45 GAP_STATIC_ASSERT(sizeof(void *) == SIZEOF_VOID_P, "sizeof(void *) is wrong");
46 
47 
48 // EXPORT_INLINE is used for most inline functions declared in our header
49 // files; it is set to `inline` by default, except in debug.c, where it is set
50 // to `extern inline`, to ensure exactly one instance of the function is
51 // actually emitted.
52 //
53 // We make an exception for HPC-GAP, were we default to `static inline`
54 // instead, to avoid warnings in code using atomic_ops functions; this is OK,
55 // as we don't support a libgap version of HPC-GAP right now, and if we ever
56 // wanted to, a lot more work (and planning) would have to be invested into
57 // that anyway.
58 #ifndef EXPORT_INLINE
59 #ifdef HPCGAP
60 #define EXPORT_INLINE static inline
61 #else
62 #define EXPORT_INLINE inline
63 #endif
64 #endif
65 
66 /****************************************************************************
67 **
68 *S  GAP_PATH_MAX . . . . . . . . . . . .  size for buffers storing file paths
69 **
70 **  'GAP_PATH_MAX' is the default buffer size GAP uses internally to store
71 **  most paths. If any longer paths are encountered, they will be either
72 **  truncated, or GAP aborts.
73 **
74 **  Note that no fixed buffer size is sufficient to store arbitrary paths
75 **  on contemporary operating systems, as paths can have arbitrary length.
76 **  This also means that the POSIX constant PATH_MAX does not really do the
77 **  job its name would suggest (nor do MAXPATHLEN, MAX_PATH etc.).
78 **
79 **  Writing POSIX compliant code without a hard coded buffer size is rather
80 **  challenging, as often there is no way to find out in advance how large a
81 **  buffer may need to be. So you have to start with some buffer size, then
82 **  check for errors; if 'errno' equals 'ERANGE', double the buffer size and
83 **  repeat, until you succeed or run out of memory.
84 **
85 **  Instead of going down this road, we use a fixed buffer size after all.
86 **  This way, at least our code stays simple. Also, this is what most (?)
87 **  code out there does, too, so if somebody actually uses such long paths,
88 **  at least GAP won't be the only program to run into problems.
89 */
90 enum {
91 #if defined(PATH_MAX) && PATH_MAX > 4096
92     GAP_PATH_MAX = PATH_MAX,
93 #else
94     GAP_PATH_MAX = 4096,
95 #endif
96 };
97 
98 
99 /****************************************************************************
100 **
101 *T  Wrappers for various compiler attributes
102 **
103 */
104 #if defined(HAVE_FUNC_ATTRIBUTE_ALWAYS_INLINE) && !defined(GAP_KERNEL_DEBUG)
105 #define ALWAYS_INLINE __attribute__((always_inline)) inline
106 #else
107 #define ALWAYS_INLINE inline
108 #endif
109 
110 #ifdef HAVE_FUNC_ATTRIBUTE_NOINLINE
111 #define NOINLINE __attribute__((noinline))
112 #else
113 #define NOINLINE
114 #endif
115 
116 #ifdef HAVE_FUNC_ATTRIBUTE_NORETURN
117 #define NORETURN __attribute__((noreturn))
118 #else
119 #define NORETURN
120 #endif
121 
122 /****************************************************************************
123 **
124 *T  Char, Int1, Int2, Int4, Int, UChar, UInt1, UInt2, UInt4, UInt .  integers
125 **
126 **  'Char', 'Int1', 'Int2', 'Int4', 'Int8', 'Int', 'UChar', 'UInt1', 'UInt2',
127 **  'UInt4', 'UInt8', 'UInt' are the integer types.
128 **
129 **  '(U)Int<n>' should be exactly <n> bytes long
130 **  '(U)Int' should be the same length as a bag identifier
131 */
132 
133 
134 typedef char     Char;
135 typedef uint8_t  UChar;
136 
137 typedef int8_t   Int1;
138 typedef int16_t  Int2;
139 typedef int32_t  Int4;
140 typedef int64_t  Int8;
141 
142 typedef uint8_t  UInt1;
143 typedef uint16_t UInt2;
144 typedef uint32_t UInt4;
145 typedef uint64_t UInt8;
146 
147 typedef intptr_t  Int;
148 typedef uintptr_t UInt;
149 
150 GAP_STATIC_ASSERT(sizeof(void *) == sizeof(Int), "sizeof(Int) is wrong");
151 GAP_STATIC_ASSERT(sizeof(void *) == sizeof(UInt), "sizeof(UInt) is wrong");
152 
153 
154 /****************************************************************************
155 **
156 **  'START_ENUM_RANGE' and 'END_ENUM_RANGE' simplify creating "ranges" of
157 **  enum variables.
158 **
159 **  Usage example:
160 **    enum {
161 **      START_ENUM_RANGE(FIRST),
162 **        FOO,
163 **        BAR,
164 **      END_ENUM_RANGE(LAST)
165 **    };
166 **  is essentially equivalent to
167 **    enum {
168 **      FIRST,
169 **        FOO = FIRST,
170 **        BAR,
171 **      LAST = BAR
172 **    };
173 **  Note that if we add a value into the range after 'BAR', we must adjust
174 **  the definition of 'LAST', which is easy to forget. Also, reordering enum
175 **  values may require extra work. With the range macros, all of this is
176 **  taken care of automatically.
177 */
178 #define START_ENUM_RANGE(id)            id, _##id##_post = id - 1
179 #define START_ENUM_RANGE_INIT(id,init)  id = init, _##id##_post = id - 1
180 #define END_ENUM_RANGE(id)              _##id##_pre, id = _##id##_pre - 1
181 
182 
183 /****************************************************************************
184 **
185 *t  Bag . . . . . . . . . . . . . . . . . . . type of the identifier of a bag
186 **
187 **  (The documentation of 'Bag' is contained in 'gasman.h'.)
188 */
189 typedef UInt * *        Bag;
190 
191 
192 /****************************************************************************
193 **
194 *T  Obj . . . . . . . . . . . . . . . . . . . . . . . . . . . type of objects
195 **
196 **  'Obj' is the type of objects.
197 */
198 typedef Bag Obj;
199 
200 
201 /****************************************************************************
202 **
203 *T  ObjFunc . . . . . . . . . . . . . . . . type of function returning object
204 **
205 **  'ObjFunc' is the type of a function returning an object.
206 */
207 #pragma GCC diagnostic push
208 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
209 typedef Obj (* ObjFunc) (/*arguments*/);
210 #pragma GCC diagnostic pop
211 
212 
213 /****************************************************************************
214 **
215 *T  Stat  . . . . . . . . . . . . . . . . . . . . . . . .  type of statements
216 **
217 **  'Stat' is the type of statements.
218 **
219 **  If 'Stat' is different  from 'Expr', then  a lot of things will  probably
220 **  break.
221 */
222 typedef UInt Stat;
223 
224 
225 /****************************************************************************
226 **
227 *T  Expr  . . . . . . . . . . . . . . . . . . . . . . . . type of expressions
228 **
229 **  'Expr' is the type of expressions.
230 **
231 **  If 'Expr' is different  from 'Stat', then  a lot of things will  probably
232 **  break.
233 */
234 typedef Stat Expr;
235 
236 
237 /****************************************************************************
238 **
239 *V  BIPEB . . . . . . . . . . . . . . . . . . . . . . . . . .  bits per block
240 **
241 **  'BIPEB' is the  number of bits  per  block, where a  block  fills a UInt,
242 **  which must be the same size as a bag identifier.
243 **  'LBIPEB' is the log to the base 2 of BIPEB
244 **
245 */
246 enum { BIPEB = sizeof(UInt) * 8L, LBIPEB = (BIPEB == 64) ? 6L : 5L };
247 
248 
249 /****************************************************************************
250 **
251 *F * * * * * * * * * * * * * time related functions * * * * * * * * * * * * *
252 */
253 
254 /****************************************************************************
255 **
256 *F  SyTime()  . . . . . . . . . . . . . . . return time spent in milliseconds
257 **
258 **  'SyTime' returns the number of milliseconds spent by GAP so far.
259 **
260 **  Should be as accurate as possible,  because it  is  used  for  profiling.
261 */
262 UInt SyTime(void);
263 
264 /* TODO: Properly document the following three calls */
265 UInt SyTimeSys(void);
266 UInt SyTimeChildren(void);
267 UInt SyTimeChildrenSys(void);
268 
269 /****************************************************************************
270 **
271 *F * * * * * * * * * * * * * * * string functions * * * * * * * * * * * * * *
272 */
273 
274 
275 /****************************************************************************
276 **
277 *F  IsAlpha( <ch> ) . . . . . . . . . . . . .  is a character a normal letter
278 **
279 **  'IsAlpha' returns 1 if its character argument is a normal character  from
280 **  the range 'a..zA..Z' and 0 otherwise.
281 */
282 #define IsAlpha(ch)     (isalpha((unsigned int)ch))
283 
284 
285 /****************************************************************************
286 **
287 *F  IsDigit( <ch> ) . . . . . . . . . . . . . . . . .  is a character a digit
288 **
289 **  'IsDigit' returns 1 if its character argument is a digit from  the  range
290 **  '0..9' and 0 otherwise.
291 */
292 #define IsDigit(ch)     (isdigit((unsigned int)ch))
293 
294 
295 /****************************************************************************
296 **
297 *F  strlcpy( <dst>, <src>, <len> )
298 **
299 **  Copy <src> to buffer <dst> of size <len>. At most <len>-1 characters will
300 **  be copied. Afterwards, <dst> is always 'NUL' terminated
301 **  (unless <len> == 0).
302 **
303 **  Returns 'strlen( <src> )'; hence if the return value is greater or equal
304 **  than <len>, truncation occurred.
305 **
306 **  This function is provided by some systems (e.g. OpenBSD, Mac OS X),
307 **  but not by all, so we provide a fallback implementation for those
308 **  systems that lack it.
309 */
310 #ifndef HAVE_STRLCPY
311 size_t strlcpy (
312     char *dst,
313     const char *src,
314     size_t len);
315 #endif
316 
317 /****************************************************************************
318 **
319 *F  strlcat( <dst>, <src>, <len> )
320 **
321 **  Appends <src> to buffer <dst> of size <len> (unlike 'strncat', <len> is
322 **  the full size of <dst>, not space left).
323 **  At most <len>-1 characters will be copied.
324 **  Afterwards, <dst> is always 'NUL' terminated (unless <len> == 0).
325 **
326 **  Returns initial length of <dst> plus 'strlen(<src>)'; hence if the return
327 **  value is greater or equal than <len>, truncation occurred.
328 **
329 **  This function is provided by some systems (e.g. OpenBSD, Mac OS X),
330 **  but not by all, so we provide a fallback implementation for those
331 **  systems that lack it.
332 */
333 #ifndef HAVE_STRLCAT
334 size_t strlcat (
335     char *dst,
336     const char *src,
337     size_t len);
338 #endif
339 
340 /****************************************************************************
341 **
342 *F  strxcpy( <dst>, <src>, <len> )
343 **
344 **  Copy <src> to buffer <dst> of size <len>.
345 **  If an overflow would occur, trigger an assertion.
346 **
347 **  This should be used with caution; in general, proper error handling is
348 **  preferable.
349 **/
350 size_t strxcpy (
351     char *dst,
352     const char *src,
353     size_t len);
354 
355 /****************************************************************************
356 **
357 *F  strxcat( <dst>, <src>, <len> )
358 **
359 **  Append <src> to buffer <dst> of size <len>.
360 **  If an overflow would occur, trigger an assertion.
361 **
362 **  This should be used with caution; in general, proper error handling is
363 **  preferable.
364 **/
365 size_t strxcat (
366     char *dst,
367     const char *src,
368     size_t len);
369 
370 
371 typedef const struct init_info StructInitInfo;
372 typedef StructInitInfo* (*InitInfoFunc)(void);
373 
374 
375 /****************************************************************************
376 **
377 *F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
378 */
379 
380 /****************************************************************************
381 **
382 *F  SyExit( <ret> ) . . . . . . . . . . . . . exit GAP with return code <ret>
383 **
384 **  'SyExit' is the offical  way  to  exit GAP, bus errors are the inoffical.
385 **  The function 'SyExit' must perform all the neccessary cleanup operations.
386 **  If ret is 0 'SyExit' should signal to a calling proccess that all is  ok.
387 **  If ret is 1 'SyExit' should signal a  failure  to  the  calling proccess.
388 */
389 void SyExit(UInt ret) NORETURN;
390 
391 
392 /****************************************************************************
393 **
394 *F  Panic( <msg> )
395 */
396 void Panic_(const char * file, int line, const char * fmt, ...) NORETURN
397 #ifdef HAVE_FUNC_ATTRIBUTE_FORMAT
398     __attribute__((format(printf, 3, 4)))
399 #endif
400     ;
401 #define Panic(...) \
402     Panic_(__FILE__, __LINE__, __VA_ARGS__)
403 
404 
405 /****************************************************************************
406 **
407 *F  SyNanosecondsSinceEpoch()
408 **
409 **  'SyNanosecondsSinceEpoch' returns a 64-bit integer which represents the
410 **  number of nanoseconds since some unspecified starting point. This means
411 **  that the number returned by this function is not in itself meaningful,
412 **  but the difference between the values returned by two consecutive calls
413 **  can be used to measure wallclock time.
414 **
415 **  The accuracy of this is system dependent. For systems that implement
416 **  clock_getres, we could get the promised accuracy.
417 **
418 **  Note that gettimeofday has been marked obsolete in the POSIX standard.
419 **  We are using it because it is implemented in most systems still.
420 **
421 **  If we are using gettimeofday we cannot guarantee the values that
422 **  are returned by SyNanosecondsSinceEpoch to be monotonic.
423 **
424 **  Returns -1 to represent failure
425 **
426 */
427 Int8 SyNanosecondsSinceEpoch(void);
428 Int8 SyNanosecondsSinceEpochResolution(void);
429 
430 extern const char * const SyNanosecondsSinceEpochMethod;
431 extern const Int SyNanosecondsSinceEpochMonotonic;
432 
433 /****************************************************************************
434 **
435 *F  SySleep( <secs> ) . . . . . . . . . . . . Try to sleep for <secs> seconds
436 **
437 **  The OS may wake us earlier, for example on receipt of a signal
438 */
439 
440 void SySleep(UInt secs);
441 
442 /****************************************************************************
443 **
444 *F  SyUSleep( <msecs> ) . . . . . . . . .Try to sleep for <msecs> microseconds
445 **
446 **  The OS may wake us earlier, for example on receipt of a signal
447 */
448 
449 void SyUSleep(UInt msecs);
450 
451 /****************************************************************************
452 **
453 *F  sySetjmp( <jump buffer> )
454 *F  syLongjmp( <jump buffer>, <value> )
455 **
456 **  macros and functions, defining our selected longjump mechanism
457 */
458 
459 #if defined(HAVE_SIGSETJMP)
460 #define sySetjmp( buff ) (sigsetjmp( (buff), 0))
461 #define syLongjmpInternal siglongjmp
462 #define syJmp_buf sigjmp_buf
463 #elif defined(HAVE__SETJMP)
464 #define sySetjmp _setjmp
465 #define syLongjmpInternal _longjmp
466 #define syJmp_buf jmp_buf
467 #else
468 #define sySetjmp setjmp
469 #define syLongjmpInternal longjmp
470 #define syJmp_buf jmp_buf
471 #endif
472 
473 void syLongjmp(syJmp_buf * buf, int val) NORETURN;
474 
475 /****************************************************************************
476 **
477 *F  RegisterSyLongjmpObserver( <func> )
478 **
479 **  register a function to be called before longjmp is called.
480 */
481 
482 typedef void (*voidfunc)(void);
483 
484 Int RegisterSyLongjmpObserver(voidfunc);
485 
486 
487 /****************************************************************************
488 **
489 *F  InitSystem( <argc>, <argv>, <handleSignals> ) . initialize system package
490 **
491 **  'InitSystem' is called very early during the initialization from  'main'.
492 **  It is passed the command line array  <argc>, <argv>  to look for options.
493 **
494 **  For UNIX it initializes the default files 'stdin', 'stdout' and 'stderr',
495 **  and if handleSignals is non-zero installs the handler 'syAnswerIntr' to
496 **  answer the user interrupts '<ctr>-C', scans the command line for options,
497 **  sets up the GAP root paths, locates the '.gaprc' file (if any), and more.
498 */
499 void InitSystem(Int argc, Char * argv[], UInt handleSignals);
500 
501 #endif // GAP_SYSTEM_H
502