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