LCOV - code coverage report
Current view: top level - gdk - gdk_utils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 553 841 65.8 %
Date: 2021-09-14 19:48:19 Functions: 47 51 92.2 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * @a M. L. Kersten, P. Boncz, N. Nes
      11             :  *
      12             :  * @* Utilities
      13             :  * The utility section contains functions to initialize the Monet
      14             :  * database system, memory allocation details, and a basic system
      15             :  * logging scheme.
      16             :  */
      17             : #include "monetdb_config.h"
      18             : #include "monet_options.h"
      19             : 
      20             : #include "gdk.h"
      21             : #include "gdk_private.h"
      22             : #include "mutils.h"
      23             : 
      24             : static BAT *GDKkey = NULL;
      25             : static BAT *GDKval = NULL;
      26             : int GDKdebug = 0;
      27             : 
      28             : #include <signal.h>
      29             : 
      30             : #ifdef HAVE_FCNTL_H
      31             : #include <fcntl.h>
      32             : #endif
      33             : 
      34             : #ifdef HAVE_PWD_H
      35             : # include <pwd.h>
      36             : #endif
      37             : 
      38             : #ifdef HAVE_SYS_PARAM_H
      39             : # include <sys/param.h>  /* prerequisite of sys/sysctl on OpenBSD */
      40             : #endif
      41             : #ifdef BSD /* BSD macro is defined in sys/param.h */
      42             : # include <sys/sysctl.h>
      43             : #endif
      44             : #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
      45             : #include <sys/resource.h>
      46             : #endif
      47             : 
      48             : #ifdef __CYGWIN__
      49             : #include <sysinfoapi.h>
      50             : #endif
      51             : 
      52             : static ATOMIC_TYPE GDKstopped = ATOMIC_VAR_INIT(0);
      53             : static void GDKunlockHome(int farmid);
      54             : 
      55             : #undef malloc
      56             : #undef calloc
      57             : #undef realloc
      58             : #undef free
      59             : 
      60             : /* when the number of updates to a BAT is less than 1 in this number, we
      61             :  * keep the GDK_UNIQUE_ESTIMATE property */
      62             : BUN GDK_UNIQUE_ESTIMATE_KEEP_FRACTION = 1000; /* should become a define once */
      63             : /* if the number of unique values is less than 1 in this number, we
      64             :  * destroy the hash rather than update it in HASH{append,insert,delete} */
      65             : BUN HASH_DESTROY_UNIQUES_FRACTION = 1000;     /* likewise */
      66             : /* if the estimated number of unique values is less than 1 in this
      67             :  * number, don't build a hash table to do a hashselect */
      68             : dbl NO_HASH_SELECT_FRACTION = 1000;           /* same here */
      69             : 
      70             : /*
      71             :  * @+ Monet configuration file
      72             :  * Parse a possible MonetDB config file (if specified by command line
      73             :  * option -c/--config) to extract pre-settings of system variables.
      74             :  * Un-recognized parameters are simply skipped, because they may be
      75             :  * picked up by other components of the system.  The consequence is
      76             :  * that making a typing error in the configuration file may be
      77             :  * unnoticed for a long time.  Syntax errors are immediately flagged,
      78             :  * though.
      79             :  *
      80             :  * Since the GDK kernel moves into the database directory, we need to
      81             :  * keep the absolute path to the MonetDB config file for top-levels to
      82             :  * access its information.
      83             :  */
      84             : 
      85             : static bool
      86         267 : GDKenvironment(const char *dbpath)
      87             : {
      88         267 :         if (dbpath == NULL) {
      89           0 :                 TRC_CRITICAL(GDK, "Database name missing.\n");
      90           0 :                 return false;
      91             :         }
      92         267 :         if (strlen(dbpath) >= FILENAME_MAX) {
      93           0 :                 TRC_CRITICAL(GDK, "Database name too long.\n");
      94           0 :                 return false;
      95             :         }
      96         267 :         if (!GDKembedded() && !MT_path_absolute(dbpath)) {
      97           0 :                 TRC_CRITICAL(GDK, "Directory not an absolute path: %s.\n", dbpath);
      98           0 :                 return false;
      99             :         }
     100             :         return true;
     101             : }
     102             : 
     103             : static struct orig_value {
     104             :         struct orig_value *next;
     105             :         char *value;
     106             :         char key[];
     107             : } *orig_value;
     108             : static MT_Lock GDKenvlock = MT_LOCK_INITIALIZER(GDKenvlock);
     109             : 
     110             : const char *
     111      263636 : GDKgetenv(const char *name)
     112             : {
     113      263636 :         MT_lock_set(&GDKenvlock);
     114      263638 :         for (struct orig_value *ov = orig_value; ov; ov = ov->next) {
     115           0 :                 if (strcmp(ov->key, name) == 0) {
     116           0 :                         MT_lock_unset(&GDKenvlock);
     117           0 :                         return ov->value;
     118             :                 }
     119             :         }
     120      263638 :         MT_lock_unset(&GDKenvlock);
     121      263638 :         if (GDKkey && GDKval) {
     122      263636 :                 BUN b = BUNfnd(GDKkey, name);
     123             : 
     124      263636 :                 if (b != BUN_NONE) {
     125      178278 :                         BATiter GDKenvi = bat_iterator(GDKval);
     126      178278 :                         const char *v = BUNtvar(GDKenvi, b);
     127      178278 :                         bat_iterator_end(&GDKenvi);
     128             :                         return v;
     129             :                 }
     130             :         }
     131             :         return NULL;
     132             : }
     133             : 
     134             : bool
     135      169998 : GDKgetenv_istext(const char *name, const char *text)
     136             : {
     137      169998 :         const char *val = GDKgetenv(name);
     138             : 
     139      169998 :         return val && strcasecmp(val, text) == 0;
     140             : }
     141             : 
     142             : bool
     143        4939 : GDKgetenv_isyes(const char *name)
     144             : {
     145        4939 :         return GDKgetenv_istext(name, "yes");
     146             : }
     147             : 
     148             : bool
     149      165059 : GDKgetenv_istrue(const char *name)
     150             : {
     151      165059 :         return GDKgetenv_istext(name, "true");
     152             : }
     153             : 
     154             : int
     155       75776 : GDKgetenv_int(const char *name, int def)
     156             : {
     157       75776 :         const char *val = GDKgetenv(name);
     158             : 
     159       75778 :         if (val)
     160         254 :                 return atoi(val);
     161             :         return def;
     162             : }
     163             : 
     164             : #define ESCAPE_CHAR     '%'
     165             : 
     166             : static bool
     167        6099 : isutf8(const char *v, size_t *esclen)
     168             : {
     169             :         size_t n = 1;
     170             :         int nutf8 = 0;
     171             :         int m = 0;
     172      105045 :         for (size_t i = 0; v[i]; i++) {
     173       98946 :                 if (nutf8 > 0) {
     174           8 :                         if ((v[i] & 0xC0) != 0x80 ||
     175           0 :                             (m != 0 && (v[i] & m) == 0))
     176           0 :                                 goto badutf8;
     177             :                         m = 0;
     178           8 :                         nutf8--;
     179       98938 :                 } else if ((v[i] & 0xE0) == 0xC0) {
     180             :                         nutf8 = 1;
     181           0 :                         if ((v[i] & 0x1E) == 0)
     182           0 :                                 goto badutf8;
     183       98938 :                 } else if ((v[i] & 0xF0) == 0xE0) {
     184             :                         nutf8 = 2;
     185           4 :                         if ((v[i] & 0x0F) == 0)
     186             :                                 m = 0x20;
     187       98934 :                 } else if ((v[i] & 0xF8) == 0xF0) {
     188             :                         nutf8 = 3;
     189           0 :                         if ((v[i] & 0x07) == 0)
     190             :                                 m = 0x30;
     191       98934 :                 } else if ((v[i] & 0x80) != 0) {
     192           0 :                         goto badutf8;
     193             :                 }
     194             :         }
     195        6099 :         *esclen = 0;
     196        6099 :         return true;
     197           0 :   badutf8:
     198           0 :         for (size_t i = 0; v[i]; i++) {
     199           0 :                 if (v[i] & 0x80 || v[i] == ESCAPE_CHAR)
     200           0 :                         n += 3;
     201             :                 else
     202           0 :                         n++;
     203             :         }
     204           0 :         *esclen = n;
     205           0 :         return false;
     206             : }
     207             : 
     208             : gdk_return
     209        6099 : GDKsetenv(const char *name, const char *value)
     210             : {
     211             :         static const char hexdigits[] = "0123456789abcdef";
     212             :         char *conval = NULL;
     213        6099 :         size_t esclen = 0;
     214        6099 :         if (!isutf8(value, &esclen)) {
     215           0 :                 size_t j = strlen(name) + 1;
     216           0 :                 struct orig_value *ov = GDKmalloc(offsetof(struct orig_value, key) + j + strlen(value) + 1);
     217           0 :                 if (ov == NULL)
     218             :                         return GDK_FAIL;
     219           0 :                 strcpy(ov->key, name);
     220           0 :                 ov->value = ov->key + j;
     221           0 :                 strcpy(ov->value, value);
     222           0 :                 conval = GDKmalloc(esclen);
     223           0 :                 if (conval == NULL) {
     224           0 :                         GDKfree(ov);
     225           0 :                         return GDK_FAIL;
     226             :                 }
     227             :                 j = 0;
     228           0 :                 for (size_t i = 0; value[i]; i++) {
     229           0 :                         if (value[i] & 0x80 || value[i] == ESCAPE_CHAR) {
     230           0 :                                 conval[j++] = ESCAPE_CHAR;
     231           0 :                                 conval[j++] = hexdigits[(unsigned char) value[i] >> 4];
     232           0 :                                 conval[j++] = hexdigits[(unsigned char) value[i] & 0xF];
     233             :                         } else {
     234           0 :                                 conval[j++] = value[i];
     235             :                         }
     236             :                 }
     237           0 :                 conval[j] = 0;
     238           0 :                 MT_lock_set(&GDKenvlock);
     239           0 :                 ov->next = orig_value;
     240           0 :                 orig_value = ov;
     241             :                 /* remove previous value if present (later in list) */
     242           0 :                 for (ov = orig_value; ov->next; ov = ov->next) {
     243           0 :                         if (strcmp(ov->next->key, name) == 0) {
     244             :                                 struct orig_value *ovn = ov->next;
     245           0 :                                 ov->next = ovn->next;
     246           0 :                                 GDKfree(ovn);
     247             :                         }
     248             :                 }
     249           0 :                 MT_lock_unset(&GDKenvlock);
     250             :         } else {
     251             :                 /* remove previous value if present */
     252        6099 :                 MT_lock_set(&GDKenvlock);
     253        6099 :                 for (struct orig_value **ovp = &orig_value; *ovp; ovp = &(*ovp)->next) {
     254           0 :                         if (strcmp((*ovp)->key, name) == 0) {
     255             :                                 struct orig_value *ov = *ovp;
     256           0 :                                 *ovp = ov->next;
     257           0 :                                 GDKfree(ov);
     258           0 :                                 break;
     259             :                         }
     260             :                 }
     261        6099 :                 MT_lock_unset(&GDKenvlock);
     262             :         }
     263        6099 :         BUN p = BUNfnd(GDKkey, name);
     264             :         gdk_return rc;
     265        6099 :         if (p != BUN_NONE) {
     266        1016 :                 rc = BUNreplace(GDKval, p + GDKval->hseqbase,
     267             :                                 conval ? conval : value, false);
     268             :         } else {
     269        5591 :                 rc = BUNappend(GDKkey, name, false);
     270        5591 :                 if (rc == GDK_SUCCEED)
     271       11182 :                         rc = BUNappend(GDKval, conval ? conval : value, false);
     272             :         }
     273        6099 :         GDKfree(conval);
     274        6099 :         return rc;
     275             : }
     276             : 
     277             : gdk_return
     278          38 : GDKcopyenv(BAT **key, BAT **val, bool writable)
     279             : {
     280             :         BAT *k, *v;
     281             : 
     282          38 :         if (key == NULL || val == NULL) {
     283           0 :                 GDKerror("called incorrectly.\n");
     284           0 :                 return GDK_FAIL;
     285             :         }
     286          38 :         k = COLcopy(GDKkey, GDKkey->ttype, writable, TRANSIENT);
     287          38 :         v = COLcopy(GDKval, GDKval->ttype, writable, TRANSIENT);
     288          38 :         if (k == NULL || v == NULL) {
     289           0 :                 BBPreclaim(k);
     290           0 :                 BBPreclaim(v);
     291           0 :                 return GDK_FAIL;
     292             :         }
     293          38 :         *key = k;
     294          38 :         *val = v;
     295          38 :         return GDK_SUCCEED;
     296             : }
     297             : 
     298             : 
     299             : /*
     300             :  * @+ System logging
     301             :  * Per database a log file can be maintained for collection of system
     302             :  * management information. Its contents is driven by the upper layers,
     303             :  * which encode information such as who logged on and how long the
     304             :  * session went on.  The lower layers merely store error information
     305             :  * on the file.  It should not be used for crash recovery, because
     306             :  * this should be dealt with on a per client basis.
     307             :  *
     308             :  * A system log can be maintained in the database to keep track of
     309             :  * session and crash information. It should regularly be refreshed to
     310             :  * avoid disk overflow.
     311             :  */
     312             : #define GDKLOCK ".gdk_lock"
     313             : 
     314             : #define GET_GDKLOCK(x) BBPfarms[BBPselectfarm((x), 0, offheap)].lock_file
     315             : 
     316             : #define GDKLOGOFF       "LOGOFF"
     317             : #define GDKFOUNDDEAD    "FOUND     DEAD"
     318             : #define GDKLOGON        "LOGON"
     319             : #define GDKCRASH        "CRASH"
     320             : 
     321             : /*
     322             :  * Single-lined comments can now be logged safely, together with
     323             :  * process, thread and user ID, and the current time.
     324             :  */
     325             : void
     326         674 : GDKlog(FILE *lockFile, const char *format, ...)
     327             : {
     328             :         va_list ap;
     329             :         char *p = 0, buf[1024];
     330         674 :         time_t tm = time(0);
     331             : #if defined(HAVE_CTIME_R3) || defined(HAVE_CTIME_R)
     332             :         char tbuf[26];
     333             : #endif
     334             :         char *ctm;
     335             : 
     336         674 :         if (MT_pagesize() == 0 || lockFile == NULL)
     337           1 :                 return;
     338             : 
     339         673 :         va_start(ap, format);
     340         673 :         vsnprintf(buf, sizeof(buf), format, ap);
     341         673 :         va_end(ap);
     342             : 
     343             :         /* remove forbidden characters from message */
     344         673 :         for (p = buf; (p = strchr(p, '\n')) != NULL; *p = ' ')
     345             :                 ;
     346         673 :         for (p = buf; (p = strchr(p, '@')) != NULL; *p = ' ')
     347             :                 ;
     348             : 
     349         673 :         fseek(lockFile, 0, SEEK_END);
     350             : #ifndef HAVE_GETUID
     351             : #define getuid() 0
     352             : #endif
     353             : #ifdef HAVE_CTIME_R3
     354             :         ctm = ctime_r(&tm, tbuf, sizeof(tbuf));
     355             : #else
     356         673 :         ctm = ctime_r(&tm, tbuf);
     357             : #endif
     358         673 :         fprintf(lockFile, "USR=%d PID=%d TIME=%.24s @ %s\n", (int) getuid(), (int) getpid(), ctm, buf);
     359         673 :         fflush(lockFile);
     360             : }
     361             : 
     362             : /*
     363             :  * @+ Interrupt handling
     364             :  * The current version simply catches signals and prints a warning.
     365             :  * It should be extended to cope with the specifics of the interrupt
     366             :  * received.
     367             :  */
     368             : #if 0                           /* these are unused */
     369             : static void
     370             : BATSIGignore(int nr)
     371             : {
     372             :         (void) nr;
     373             :         GDKsyserror("! ERROR signal %d caught by thread %zu\n", nr, (size_t) MT_getpid());
     374             : }
     375             : #endif
     376             : 
     377             : #ifdef WIN32
     378             : static void
     379             : BATSIGabort(int nr)
     380             : {
     381             :         (void) nr;
     382             :         _Exit(3);               /* emulate Windows exit code without pop-up */
     383             : }
     384             : #endif
     385             : 
     386             : #ifndef NATIVE_WIN32
     387             : static void
     388             : BATSIGinit(void)
     389             : {
     390             : #ifdef SIGPIPE
     391         268 :         (void) signal(SIGPIPE, SIG_IGN);
     392             : #endif
     393             : }
     394             : #endif /* NATIVE_WIN32 */
     395             : 
     396             : /* memory thresholds; these values some "sane" constants only, really
     397             :  * set in GDKinit() */
     398             : #define MMAP_MINSIZE_PERSISTENT ((size_t) 1 << 18)
     399             : #if SIZEOF_SIZE_T == 4
     400             : #define MMAP_MINSIZE_TRANSIENT  ((size_t) 1 << 20)
     401             : #else
     402             : #define MMAP_MINSIZE_TRANSIENT  ((size_t) 1 << 32)
     403             : #endif
     404             : #define MMAP_PAGESIZE           ((size_t) 1 << 16)
     405             : size_t GDK_mmap_minsize_persistent = MMAP_MINSIZE_PERSISTENT;
     406             : size_t GDK_mmap_minsize_transient = MMAP_MINSIZE_TRANSIENT;
     407             : size_t GDK_mmap_pagesize = MMAP_PAGESIZE; /* mmap granularity */
     408             : size_t GDK_mem_maxsize = GDK_VM_MAXSIZE;
     409             : size_t GDK_vm_maxsize = GDK_VM_MAXSIZE;
     410             : 
     411             : #define SEG_SIZE(x,y)   ((x)+(((x)&((1<<(y))-1))?(1<<(y))-((x)&((1<<(y))-1)):0))
     412             : 
     413             : /* This block is to provide atomic addition and subtraction to select
     414             :  * variables.  We use intrinsic functions (recognized and inlined by
     415             :  * the compiler) for both the GNU C compiler and Microsoft Visual
     416             :  * Studio.  By doing this, we avoid locking overhead.  There is also a
     417             :  * fall-back for other compilers. */
     418             : #include "matomic.h"
     419             : static ATOMIC_TYPE GDK_mallocedbytes_estimate = ATOMIC_VAR_INIT(0);
     420             : #ifndef NDEBUG
     421             : static volatile lng GDK_malloc_success_count = -1;
     422             : #endif
     423             : static ATOMIC_TYPE GDK_vm_cursize = ATOMIC_VAR_INIT(0);
     424             : 
     425             : size_t _MT_pagesize = 0;        /* variable holding page size */
     426             : size_t _MT_npages = 0;          /* variable holding memory size in pages */
     427             : 
     428             : static lng programepoch;
     429             : 
     430             : void
     431         269 : MT_init(void)
     432             : {
     433         269 :         programepoch = GDKusec();
     434             : #ifdef _MSC_VER
     435             :         {
     436             :                 SYSTEM_INFO sysInfo;
     437             : 
     438             :                 GetSystemInfo(&sysInfo);
     439             :                 _MT_pagesize = sysInfo.dwPageSize;
     440             :         }
     441             : #elif defined(BSD) && defined(HW_PAGESIZE)
     442             :         {
     443             :                 int size;
     444             :                 size_t len = sizeof(int);
     445             :                 int mib[2];
     446             : 
     447             :                 /* Everyone should have permission to make this call,
     448             :                  * if we get a failure something is really wrong. */
     449             :                 mib[0] = CTL_HW;
     450             :                 mib[1] = HW_PAGESIZE;
     451             :                 sysctl(mib, 2, &size, &len, NULL, 0);
     452             :                 _MT_pagesize = size;
     453             :         }
     454             : #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
     455         269 :         _MT_pagesize = (size_t)sysconf(_SC_PAGESIZE);
     456             : #endif
     457         269 :         if (_MT_pagesize <= 0)
     458           0 :                 _MT_pagesize = 4096;    /* default */
     459             : 
     460             : #ifdef WIN32
     461             :         {
     462             :                 MEMORYSTATUSEX memStatEx;
     463             : 
     464             :                 memStatEx.dwLength = sizeof(memStatEx);
     465             :                 if (GlobalMemoryStatusEx(&memStatEx))
     466             :                         _MT_npages = (size_t) (memStatEx.ullTotalPhys / _MT_pagesize);
     467             :         }
     468             : #elif defined(BSD) && defined(HW_MEMSIZE) && SIZEOF_SIZE_T == SIZEOF_LNG
     469             :         /* Darwin, 64-bits */
     470             :         {
     471             :                 uint64_t size = 0;
     472             :                 size_t len = sizeof(size);
     473             :                 int mib[2];
     474             : 
     475             :                 /* Everyone should have permission to make this call,
     476             :                  * if we get a failure something is really wrong. */
     477             :                 mib[0] = CTL_HW;
     478             :                 mib[1] = HW_MEMSIZE;
     479             :                 sysctl(mib, 2, &size, &len, NULL, 0);
     480             :                 _MT_npages = size / _MT_pagesize;
     481             :         }
     482             : #elif defined(BSD) && defined (HW_PHYSMEM64) && SIZEOF_SIZE_T == SIZEOF_LNG
     483             :         /* OpenBSD, 64-bits */
     484             :         {
     485             :                 int64_t size = 0;
     486             :                 size_t len = sizeof(size);
     487             :                 int mib[2];
     488             : 
     489             :                 /* Everyone should have permission to make this call,
     490             :                  * if we get a failure something is really wrong. */
     491             :                 mib[0] = CTL_HW;
     492             :                 mib[1] = HW_PHYSMEM64;
     493             :                 sysctl(mib, 2, &size, &len, NULL, 0);
     494             :                 _MT_npages = size / _MT_pagesize;
     495             :         }
     496             : #elif defined(BSD) && defined(HW_PHYSMEM)
     497             :         /* NetBSD, OpenBSD, Darwin, 32-bits; FreeBSD 32 & 64-bits */
     498             :         {
     499             : # ifdef __FreeBSD__
     500             :                 unsigned long size = 0; /* type long required by sysctl() (?) */
     501             : # else
     502             :                 int size = 0;
     503             : # endif
     504             :                 size_t len = sizeof(size);
     505             :                 int mib[2];
     506             : 
     507             :                 /* Everyone should have permission to make this call,
     508             :                  * if we get a failure something is really wrong. */
     509             :                 mib[0] = CTL_HW;
     510             :                 mib[1] = HW_PHYSMEM;
     511             :                 sysctl(mib, 2, &size, &len, NULL, 0);
     512             :                 _MT_npages = size / _MT_pagesize;
     513             :         }
     514             : #elif defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
     515         269 :         _MT_npages = (size_t)sysconf(_SC_PHYS_PAGES);
     516             : # if SIZEOF_SIZE_T == SIZEOF_INT
     517             :         /* Bug #2935: the value returned here can be more than what can be
     518             :          * addressed on Solaris, so cap the value */
     519             :         if (UINT_MAX / _MT_pagesize < _MT_npages)
     520             :                 _MT_npages = UINT_MAX / _MT_pagesize;
     521             : # endif
     522             : #else
     523             : # error "don't know how to get the amount of physical memory for your OS"
     524             : #endif
     525             : 
     526             : #ifdef __linux__
     527             :         /* limit values to whatever cgroups gives us */
     528             :         FILE *fc;
     529             :         char buf[1024];
     530         269 :         char cgr1[1024] = "/sys/fs/cgroup/memory";
     531         269 :         char cgr2[1024] = "/sys/fs/cgroup";
     532         269 :         fc = fopen("/proc/self/mountinfo", "r");
     533         269 :         if (fc != NULL) {
     534        7285 :                 while (fgets(buf, (int) sizeof(buf), fc) != NULL) {
     535             :                         char *p, *cgr;
     536        7016 :                         if ((p = strstr(buf, " - cgroup ")) != NULL &&
     537           0 :                             strstr(p, "memory") != NULL)
     538             :                                 cgr = cgr1;
     539        7016 :                         else if (strstr(buf, " - cgroup2 ") != NULL)
     540             :                                 cgr = cgr2;
     541             :                         else
     542        6747 :                                 continue;
     543             :                         /* buf points at mount ID */
     544         269 :                         p = strchr(buf, ' ');
     545         269 :                         if (p == NULL)
     546             :                                 break;
     547         269 :                         p++;
     548             :                         /* p points at parent ID */
     549         269 :                         p = strchr(p, ' ');
     550         269 :                         if (p == NULL)
     551             :                                 break;
     552         269 :                         p++;
     553             :                         /* p points at major:minor */
     554         269 :                         p = strchr(p, ' ');
     555         269 :                         if (p == NULL)
     556             :                                 break;
     557         269 :                         p++;
     558             :                         /* p points at root */
     559         269 :                         p = strchr(p, ' ');
     560         269 :                         if (p == NULL)
     561             :                                 break;
     562         269 :                         p++;
     563             :                         /* p points at mount point */
     564             :                         char *dir = p;
     565         269 :                         p = strchr(p, ' ');
     566         269 :                         if (p == NULL)
     567             :                                 break;
     568         269 :                         *p = 0;
     569         269 :                         strcpy_len(cgr, dir, 1024);
     570             :                 }
     571         269 :                 fclose(fc);
     572             :         }
     573         269 :         fc = fopen("/proc/self/cgroup", "r");
     574         269 :         if (fc != NULL) {
     575             :                 /* each line is of the form:
     576             :                  * hierarchy-ID:controller-list:cgroup-path
     577             :                  *
     578             :                  * For cgroup v1, the hierarchy-ID refers to the
     579             :                  * second column in /proc/cgroups (which we ignore)
     580             :                  * and the controller-list is a comma-separated list
     581             :                  * of the controllers bound to the hierarchy.  We look
     582             :                  * for the "memory" controller and use its
     583             :                  * cgroup-path.  We ignore the other lines.
     584             :                  *
     585             :                  * For cgroup v2, the hierarchy-ID is 0 and the
     586             :                  * controller-list is empty.  We just use the
     587             :                  * cgroup-path.
     588             :                  *
     589             :                  * We use the first line that we can match (either v1
     590             :                  * or v2) and for which we can open any of the files
     591             :                  * that we are looking for.
     592             :                  */
     593         269 :                 while (fgets(buf, (int) sizeof(buf), fc) != NULL) {
     594             :                         char pth[1024];
     595             :                         char *p, *q;
     596             :                         bool success = false; /* true if we can open any file */
     597             :                         FILE *f;
     598             :                         uint64_t mem;
     599             : 
     600         269 :                         p = strchr(buf, '\n');
     601         269 :                         if (p == NULL)
     602             :                                 break;
     603         269 :                         *p = 0;
     604         269 :                         if (strncmp(buf, "0::", 3) == 0) {
     605             :                                 size_t l;
     606             : 
     607             :                                 /* cgroup v2 entry */
     608         269 :                                 l = strconcat_len(pth, sizeof(pth),
     609             :                                                   cgr2, buf + 3, "/", NULL);
     610             :                                 /* hard limit */
     611         269 :                                 strcpy(pth + l, "memory.max");
     612         269 :                                 f = fopen(pth, "r");
     613         269 :                                 if (f != NULL) {
     614         269 :                                         if (fscanf(f, "%" SCNu64, &mem) == 1 && mem < (uint64_t) _MT_pagesize * _MT_npages) {
     615           0 :                                                 _MT_npages = (size_t) (mem / _MT_pagesize);
     616             :                                         }
     617             :                                         success = true;
     618             :                                         /* assume "max" if not a number */
     619         269 :                                         fclose(f);
     620             :                                 }
     621             :                                 /* soft high limit */
     622         269 :                                 strcpy(pth + l, "memory.high");
     623         269 :                                 f = fopen(pth, "r");
     624         269 :                                 if (f != NULL) {
     625         269 :                                         if (fscanf(f, "%" SCNu64, &mem) == 1 && mem < (uint64_t) _MT_pagesize * _MT_npages) {
     626           0 :                                                 _MT_npages = (size_t) (mem / _MT_pagesize);
     627             :                                         }
     628             :                                         success = true;
     629             :                                         /* assume "max" if not a number */
     630         269 :                                         fclose(f);
     631             :                                 }
     632             :                                 /* soft low limit */
     633         269 :                                 strcpy(pth + l, "memory.low");
     634         269 :                                 f = fopen(pth, "r");
     635         269 :                                 if (f != NULL) {
     636         269 :                                         if (fscanf(f, "%" SCNu64, &mem) == 1 && mem > 0 && mem < (uint64_t) _MT_pagesize * _MT_npages) {
     637           0 :                                                 _MT_npages = (size_t) (mem / _MT_pagesize);
     638             :                                         }
     639             :                                         success = true;
     640             :                                         /* assume "max" if not a number */
     641         269 :                                         fclose(f);
     642             :                                 }
     643             :                                 /* limit of memory+swap usage
     644             :                                  * we use this as maximum virtual memory size */
     645         269 :                                 strcpy(pth + l, "memory.swap.max");
     646         269 :                                 f = fopen(pth, "r");
     647         269 :                                 if (f != NULL) {
     648         269 :                                         if (fscanf(f, "%" SCNu64, &mem) == 1
     649           0 :                                             && mem < (uint64_t) GDK_vm_maxsize) {
     650           0 :                                                 GDK_vm_maxsize = (size_t) mem;
     651             :                                         }
     652             :                                         success = true;
     653         269 :                                         fclose(f);
     654             :                                 }
     655             :                         } else {
     656             :                                 /* cgroup v1 entry */
     657           0 :                                 p = strchr(buf, ':');
     658           0 :                                 if (p == NULL)
     659             :                                         break;
     660           0 :                                 q = p + 1;
     661           0 :                                 p = strchr(q, ':');
     662           0 :                                 if (p == NULL)
     663             :                                         break;
     664           0 :                                 *p++ = 0;
     665           0 :                                 if (strstr(q, "memory") == NULL)
     666           0 :                                         continue;
     667             :                                 /* limit of memory usage */
     668           0 :                                 strconcat_len(pth, sizeof(pth),
     669             :                                               cgr1, p,
     670             :                                               "/memory.limit_in_bytes",
     671             :                                               NULL);
     672           0 :                                 f = fopen(pth, "r");
     673           0 :                                 if (f == NULL) {
     674           0 :                                         strconcat_len(pth, sizeof(pth),
     675             :                                                       cgr1,
     676             :                                                       "/memory.limit_in_bytes",
     677             :                                                       NULL);
     678           0 :                                         f = fopen(pth, "r");
     679             :                                 }
     680           0 :                                 if (f != NULL) {
     681           0 :                                         if (fscanf(f, "%" SCNu64, &mem) == 1
     682           0 :                                             && mem < (uint64_t) _MT_pagesize * _MT_npages) {
     683           0 :                                                 _MT_npages = (size_t) (mem / _MT_pagesize);
     684             :                                         }
     685             :                                         success = true;
     686           0 :                                         fclose(f);
     687             :                                 }
     688             :                                 /* soft limit of memory usage */
     689           0 :                                 strconcat_len(pth, sizeof(pth),
     690             :                                               cgr1, p,
     691             :                                               "/memory.soft_limit_in_bytes",
     692             :                                               NULL);
     693           0 :                                 f = fopen(pth, "r");
     694           0 :                                 if (f == NULL) {
     695           0 :                                         strconcat_len(pth, sizeof(pth),
     696             :                                                       cgr1,
     697             :                                                       "/memory.soft_limit_in_bytes",
     698             :                                                       NULL);
     699           0 :                                         f = fopen(pth, "r");
     700             :                                 }
     701           0 :                                 if (f != NULL) {
     702           0 :                                         if (fscanf(f, "%" SCNu64, &mem) == 1
     703           0 :                                             && mem < (uint64_t) _MT_pagesize * _MT_npages) {
     704           0 :                                                 _MT_npages = (size_t) (mem / _MT_pagesize);
     705             :                                         }
     706             :                                         success = true;
     707           0 :                                         fclose(f);
     708             :                                 }
     709             :                                 /* limit of memory+swap usage
     710             :                                  * we use this as maximum virtual memory size */
     711           0 :                                 strconcat_len(pth, sizeof(pth),
     712             :                                               cgr1, p,
     713             :                                               "/memory.memsw.limit_in_bytes",
     714             :                                               NULL);
     715           0 :                                 f = fopen(pth, "r");
     716           0 :                                 if (f == NULL) {
     717           0 :                                         strconcat_len(pth, sizeof(pth),
     718             :                                                       cgr1,
     719             :                                                       "/memory.memsw.limit_in_bytes",
     720             :                                                       NULL);
     721           0 :                                         f = fopen(pth, "r");
     722             :                                 }
     723           0 :                                 if (f != NULL) {
     724           0 :                                         if (fscanf(f, "%" SCNu64, &mem) == 1
     725           0 :                                             && mem < (uint64_t) GDK_vm_maxsize) {
     726           0 :                                                 GDK_vm_maxsize = (size_t) mem;
     727             :                                         }
     728             :                                         success = true;
     729           0 :                                         fclose(f);
     730             :                                 }
     731             :                         }
     732           0 :                         if (success)
     733             :                                 break;
     734             :                 }
     735         269 :                 fclose(fc);
     736             :         }
     737             : #endif
     738             : 
     739             : #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(RLIMIT_AS)
     740             :         struct rlimit l;
     741             :         /* address space (virtual memory) limit */
     742         269 :         if (getrlimit(RLIMIT_AS, &l) == 0
     743         269 :             && l.rlim_cur != (rlim_t)RLIM_INFINITY
     744           0 :             && (size_t)l.rlim_cur < GDK_vm_maxsize) {
     745           0 :                 GDK_vm_maxsize = l.rlim_cur;
     746             :         }
     747             : #endif
     748         269 : }
     749             : 
     750             : /*
     751             :  * @+ Session Initialization
     752             :  * The interface code to the operating system is highly dependent on
     753             :  * the processing environment. It can be filtered away with
     754             :  * compile-time flags.  Suicide is necessary due to some system
     755             :  * implementation errors.
     756             :  *
     757             :  * The kernel requires file descriptors for I/O with the user.  They
     758             :  * are thread specific and should be obtained by a function.
     759             :  *
     760             :  * The arguments relevant for the kernel are extracted from the list.
     761             :  * Their value is turned into a blanc space.
     762             :  */
     763             : 
     764             : #define CATNAP          50      /* time to sleep in ms for catnaps */
     765             : 
     766             : static int THRinit(void);
     767             : static gdk_return GDKlockHome(int farmid);
     768             : 
     769             : #ifndef __COVERITY__
     770             : #ifndef NDEBUG
     771             : static MT_Lock mallocsuccesslock = MT_LOCK_INITIALIZER(mallocsuccesslock);
     772             : #endif
     773             : #endif
     774             : 
     775             : void
     776         271 : GDKsetdebug(int debug)
     777             : {
     778         271 :         GDKdebug = debug;
     779         271 :         if (debug & ACCELMASK)
     780           0 :                 GDKtracer_set_component_level("accelerator", "debug");
     781             :         else
     782         271 :                 GDKtracer_reset_component_level("accelerator");
     783         271 :         if (debug & ALGOMASK)
     784           0 :                 GDKtracer_set_component_level("algo", "debug");
     785             :         else
     786         271 :                 GDKtracer_reset_component_level("algo");
     787         271 :         if (debug & ALLOCMASK)
     788           0 :                 GDKtracer_set_component_level("alloc", "debug");
     789             :         else
     790         271 :                 GDKtracer_reset_component_level("alloc");
     791         271 :         if (debug & BATMASK)
     792           0 :                 GDKtracer_set_component_level("bat", "debug");
     793             :         else
     794         271 :                 GDKtracer_reset_component_level("bat");
     795         271 :         if (debug & CHECKMASK)
     796         269 :                 GDKtracer_set_component_level("check", "debug");
     797             :         else
     798           2 :                 GDKtracer_reset_component_level("check");
     799         271 :         if (debug & DELTAMASK)
     800           0 :                 GDKtracer_set_component_level("delta", "debug");
     801             :         else
     802         271 :                 GDKtracer_reset_component_level("delta");
     803         271 :         if (debug & HEAPMASK)
     804           0 :                 GDKtracer_set_component_level("heap", "debug");
     805             :         else
     806         271 :                 GDKtracer_reset_component_level("heap");
     807         271 :         if (debug & IOMASK)
     808           0 :                 GDKtracer_set_component_level("io", "debug");
     809             :         else
     810         271 :                 GDKtracer_reset_component_level("io");
     811         271 :         if (debug & PARMASK)
     812           0 :                 GDKtracer_set_component_level("par", "debug");
     813             :         else
     814         271 :                 GDKtracer_reset_component_level("par");
     815         271 :         if (debug & PERFMASK)
     816           0 :                 GDKtracer_set_component_level("perf", "debug");
     817             :         else
     818         271 :                 GDKtracer_reset_component_level("perf");
     819         271 :         if (debug & TEMMASK)
     820           0 :                 GDKtracer_set_component_level("tem", "debug");
     821             :         else
     822         271 :                 GDKtracer_reset_component_level("tem");
     823         271 :         if (debug & THRDMASK)
     824           0 :                 GDKtracer_set_component_level("thrd", "debug");
     825             :         else
     826         271 :                 GDKtracer_reset_component_level("thrd");
     827         271 : }
     828             : 
     829             : int
     830          17 : GDKgetdebug(void)
     831             : {
     832          17 :         int debug = GDKdebug;
     833             :         const char *lvl;
     834          17 :         lvl = GDKtracer_get_component_level("accelerator");
     835          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     836           0 :                 debug |= ACCELMASK;
     837          17 :         lvl = GDKtracer_get_component_level("algo");
     838          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     839           0 :                 debug |= ALGOMASK;
     840          17 :         lvl = GDKtracer_get_component_level("alloc");
     841          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     842           0 :                 debug |= ALLOCMASK;
     843          17 :         lvl = GDKtracer_get_component_level("bat");
     844          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     845           0 :                 debug |= BATMASK;
     846          17 :         lvl = GDKtracer_get_component_level("check");
     847          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     848           0 :                 debug |= CHECKMASK;
     849          17 :         lvl = GDKtracer_get_component_level("delta");
     850          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     851           0 :                 debug |= DELTAMASK;
     852          17 :         lvl = GDKtracer_get_component_level("heap");
     853          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     854           0 :                 debug |= HEAPMASK;
     855          17 :         lvl = GDKtracer_get_component_level("io");
     856          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     857           0 :                 debug |= IOMASK;
     858          17 :         lvl = GDKtracer_get_component_level("par");
     859          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     860           0 :                 debug |= PARMASK;
     861          17 :         lvl = GDKtracer_get_component_level("perf");
     862          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     863           0 :                 debug |= PERFMASK;
     864          17 :         lvl = GDKtracer_get_component_level("tem");
     865          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     866           0 :                 debug |= TEMMASK;
     867          17 :         lvl = GDKtracer_get_component_level("thrd");
     868          17 :         if (lvl && strcmp(lvl, "debug") == 0)
     869           0 :                 debug |= THRDMASK;
     870          17 :         return debug;
     871             : }
     872             : 
     873             : static bool Mbedded = true;
     874             : bool
     875    73251853 : GDKembedded(void)
     876             : {
     877    73251853 :         return Mbedded;
     878             : }
     879             : 
     880             : static MT_Id mainpid;
     881             : 
     882             : gdk_return
     883         268 : GDKinit(opt *set, int setlen, bool embedded)
     884             : {
     885             :         static bool first = true;
     886             :         const char *dbpath;
     887             :         const char *dbtrace;
     888             :         const char *p;
     889             :         opt *n;
     890             :         int i, nlen = 0;
     891             :         char buf[16];
     892             : 
     893         268 :         mainpid = MT_getpid();
     894             : 
     895         268 :         if (GDKinmemory(0)) {
     896             :                 dbpath = dbtrace = NULL;
     897             :         } else {
     898         267 :                 dbpath = mo_find_option(set, setlen, "gdk_dbpath");
     899         267 :                 dbtrace = mo_find_option(set, setlen, "gdk_dbtrace");
     900             :         }
     901         268 :         Mbedded = embedded;
     902             :         /* some sanity checks (should also find if symbols are not defined) */
     903             :         static_assert(sizeof(int) == sizeof(int32_t),
     904             :                       "int is not equal in size to int32_t");
     905             :         static_assert(sizeof(char) == SIZEOF_CHAR,
     906             :                       "error in configure: bad value for SIZEOF_CHAR");
     907             :         static_assert(sizeof(short) == SIZEOF_SHORT,
     908             :                       "error in configure: bad value for SIZEOF_SHORT");
     909             :         static_assert(sizeof(int) == SIZEOF_INT,
     910             :                       "error in configure: bad value for SIZEOF_INT");
     911             :         static_assert(sizeof(long) == SIZEOF_LONG,
     912             :                       "error in configure: bad value for SIZEOF_LONG");
     913             :         static_assert(sizeof(lng) == SIZEOF_LNG,
     914             :                       "error in configure: bad value for SIZEOF_LNG");
     915             : #ifdef HAVE_HGE
     916             :         static_assert(sizeof(hge) == SIZEOF_HGE,
     917             :                       "error in configure: bad value for SIZEOF_HGE");
     918             : #endif
     919             :         static_assert(sizeof(dbl) == SIZEOF_DOUBLE,
     920             :                       "error in configure: bad value for SIZEOF_DOUBLE");
     921             :         static_assert(sizeof(oid) == SIZEOF_OID,
     922             :                       "error in configure: bad value for SIZEOF_OID");
     923             :         static_assert(sizeof(void *) == SIZEOF_VOID_P,
     924             :                       "error in configure: bad value for SIZEOF_VOID_P");
     925             :         static_assert(sizeof(size_t) == SIZEOF_SIZE_T,
     926             :                       "error in configure: bad value for SIZEOF_SIZE_T");
     927             :         static_assert(SIZEOF_OID == SIZEOF_INT || SIZEOF_OID == SIZEOF_LNG,
     928             :                       "SIZEOF_OID should be equal to SIZEOF_INT or SIZEOF_LNG");
     929             :         static_assert(sizeof(uuid) == 16,
     930             :                       "sizeof(uuid) should be equal to 16");
     931             : 
     932         268 :         if (first) {
     933             :                 /* some things are really only initialized once */
     934         258 :                 if (!MT_thread_init()) {
     935           0 :                         TRC_CRITICAL(GDK, "MT_thread_init failed\n");
     936           0 :                         return GDK_FAIL;
     937             :                 }
     938             : 
     939     2113794 :                 for (i = 0; i <= BBP_BATMASK; i++) {
     940             :                         char name[MT_NAME_LEN];
     941     2113536 :                         snprintf(name, sizeof(name), "GDKswapLock%d", i);
     942     2113536 :                         MT_lock_init(&GDKbatLock[i].swap, name);
     943             :                 }
     944         258 :                 if (mnstr_init() < 0) {
     945           0 :                         TRC_CRITICAL(GDK, "mnstr_init failed\n");
     946           0 :                         return GDK_FAIL;
     947             :                 }
     948         258 :                 first = false;
     949             :         } else {
     950             :                 /* BBP was locked by BBPexit() */
     951          10 :                 BBPunlock();
     952             :         }
     953         268 :         GDKtracer_init(dbpath, dbtrace);
     954         268 :         errno = 0;
     955         268 :         if (!GDKinmemory(0) && !GDKenvironment(dbpath))
     956             :                 return GDK_FAIL;
     957             : 
     958         268 :         MT_init_posix();
     959         268 :         if (THRinit() < 0)
     960             :                 return GDK_FAIL;
     961             : #ifndef NATIVE_WIN32
     962             :         BATSIGinit();
     963             : #endif
     964             : #ifdef WIN32
     965             :         (void) signal(SIGABRT, BATSIGabort);
     966             : #if !defined(__MINGW32__) && !defined(__CYGWIN__)
     967             :         _set_abort_behavior(0, _CALL_REPORTFAULT | _WRITE_ABORT_MSG);
     968             :         _set_error_mode(_OUT_TO_STDERR);
     969             : #endif
     970             : #endif
     971         268 :         MT_init();
     972             : 
     973             :         /* now try to lock the database: go through all farms, and if
     974             :          * we see a new directory, lock it */
     975        8780 :         for (int farmid = 0; farmid < MAXFARMS; farmid++) {
     976        8514 :                 if (BBPfarms[farmid].dirname != NULL) {
     977             :                         bool skip = false;
     978         666 :                         for (int j = 0; j < farmid; j++) {
     979         254 :                                 if (BBPfarms[j].dirname != NULL &&
     980         254 :                                     strcmp(BBPfarms[farmid].dirname, BBPfarms[j].dirname) == 0) {
     981             :                                         skip = true;
     982             :                                         break;
     983             :                                 }
     984             :                         }
     985         521 :                         if (!skip && GDKlockHome(farmid) != GDK_SUCCEED)
     986             :                                 return GDK_FAIL;
     987             :                 }
     988             :         }
     989             : 
     990             :         /* Mserver by default takes 80% of all memory as a default */
     991             : #if SIZEOF_SIZE_T == 4
     992             :         if ((double) MT_npages() * (double) MT_pagesize() * 0.815 >= (double) GDK_VM_MAXSIZE)
     993             :                 GDK_mem_maxsize = GDK_VM_MAXSIZE;
     994             :         else
     995             : #endif
     996         266 :         GDK_mem_maxsize = (size_t) ((double) MT_npages() * (double) MT_pagesize() * 0.815);
     997         266 :         if (BBPinit(first) != GDK_SUCCEED)
     998             :                 return GDK_FAIL;
     999             : 
    1000         266 :         if (GDK_mem_maxsize / 16 < GDK_mmap_minsize_transient) {
    1001         256 :                 GDK_mmap_minsize_transient = GDK_mem_maxsize / 16;
    1002         256 :                 if (GDK_mmap_minsize_persistent > GDK_mmap_minsize_transient)
    1003           0 :                         GDK_mmap_minsize_persistent = GDK_mmap_minsize_transient;
    1004             :         }
    1005             : 
    1006         266 :         n = (opt *) malloc(setlen * sizeof(opt));
    1007         266 :         if (n == NULL) {
    1008           0 :                 GDKsyserror("malloc failed\n");
    1009             :                 return GDK_FAIL;
    1010             :         }
    1011             : 
    1012        3081 :         for (i = 0; i < setlen; i++) {
    1013             :                 bool done = false;
    1014             : 
    1015       11975 :                 for (int j = 0; j < nlen; j++) {
    1016        9682 :                         if (strcmp(n[j].name, set[i].name) == 0) {
    1017         522 :                                 if (n[j].kind < set[i].kind) {
    1018         522 :                                         n[j] = set[i];
    1019             :                                 }
    1020             :                                 done = true;
    1021             :                                 break;
    1022             :                         }
    1023             :                 }
    1024             :                 if (!done) {
    1025        2293 :                         n[nlen] = set[i];
    1026        2293 :                         nlen++;
    1027             :                 }
    1028             :         }
    1029             :         /* check some options before creating our first BAT */
    1030        2559 :         for (i = 0; i < nlen; i++) {
    1031        2293 :                 if (strcmp("gdk_mem_maxsize", n[i].name) == 0) {
    1032           0 :                         GDK_mem_maxsize = (size_t) strtoll(n[i].value, NULL, 10);
    1033           0 :                         GDK_mem_maxsize = MAX(1 << 26, GDK_mem_maxsize);
    1034        2293 :                 } else if (strcmp("gdk_vm_maxsize", n[i].name) == 0) {
    1035         145 :                         GDK_vm_maxsize = (size_t) strtoll(n[i].value, NULL, 10);
    1036         145 :                         GDK_vm_maxsize = MAX(1 << 30, GDK_vm_maxsize);
    1037         145 :                         if (GDK_vm_maxsize < GDK_mmap_minsize_persistent / 4)
    1038           0 :                                 GDK_mmap_minsize_persistent = GDK_vm_maxsize / 4;
    1039         145 :                         if (GDK_vm_maxsize < GDK_mmap_minsize_transient / 4)
    1040           0 :                                 GDK_mmap_minsize_transient = GDK_vm_maxsize / 4;
    1041        2148 :                 } else if (strcmp("gdk_mmap_minsize_persistent", n[i].name) == 0) {
    1042           0 :                         GDK_mmap_minsize_persistent = (size_t) strtoll(n[i].value, NULL, 10);
    1043        2148 :                 } else if (strcmp("gdk_mmap_minsize_transient", n[i].name) == 0) {
    1044           0 :                         GDK_mmap_minsize_transient = (size_t) strtoll(n[i].value, NULL, 10);
    1045        2148 :                 } else if (strcmp("gdk_mmap_pagesize", n[i].name) == 0) {
    1046           0 :                         GDK_mmap_pagesize = (size_t) strtoll(n[i].value, NULL, 10);
    1047           0 :                         if (GDK_mmap_pagesize < 1 << 12 ||
    1048           0 :                             GDK_mmap_pagesize > 1 << 20 ||
    1049             :                             /* x & (x - 1): turn off rightmost 1 bit;
    1050             :                              * i.e. if result is zero, x is power of
    1051             :                              * two */
    1052           0 :                             (GDK_mmap_pagesize & (GDK_mmap_pagesize - 1)) != 0) {
    1053           0 :                                 free(n);
    1054           0 :                                 TRC_CRITICAL(GDK, "gdk_mmap_pagesize must be power of 2 between 2**12 and 2**20\n");
    1055           0 :                                 return GDK_FAIL;
    1056             :                         }
    1057             :                 }
    1058             :         }
    1059             : 
    1060         266 :         GDKkey = COLnew(0, TYPE_str, 100, TRANSIENT);
    1061         266 :         GDKval = COLnew(0, TYPE_str, 100, TRANSIENT);
    1062         266 :         if (GDKkey == NULL || GDKval == NULL) {
    1063           0 :                 free(n);
    1064           0 :                 TRC_CRITICAL(GDK, "Could not create environment BATs");
    1065           0 :                 return GDK_FAIL;
    1066             :         }
    1067         532 :         if (BBPrename(GDKkey->batCacheid, "environment_key") != 0 ||
    1068         266 :             BBPrename(GDKval->batCacheid, "environment_val") != 0) {
    1069           0 :                 free(n);
    1070           0 :                 TRC_CRITICAL(GDK, "BBPrename of environment BATs failed");
    1071           0 :                 return GDK_FAIL;
    1072             :         }
    1073         266 :         BBP_pid(GDKkey->batCacheid) = 0;
    1074         266 :         BBP_pid(GDKval->batCacheid) = 0;
    1075             : 
    1076             :         /* store options into environment BATs */
    1077        2559 :         for (i = 0; i < nlen; i++)
    1078        2293 :                 if (GDKsetenv(n[i].name, n[i].value) != GDK_SUCCEED) {
    1079           0 :                         TRC_CRITICAL(GDK, "GDKsetenv %s failed", n[i].name);
    1080           0 :                         free(n);
    1081           0 :                         return GDK_FAIL;
    1082             :                 }
    1083         266 :         free(n);
    1084             : 
    1085         266 :         GDKnr_threads = GDKgetenv_int("gdk_nr_threads", 0);
    1086         266 :         if (GDKnr_threads == 0)
    1087         265 :                 GDKnr_threads = MT_check_nr_cores();
    1088             : 
    1089         266 :         if (!GDKinmemory(0)) {
    1090         265 :                 if ((p = GDKgetenv("gdk_dbpath")) != NULL &&
    1091         265 :                         (p = strrchr(p, DIR_SEP)) != NULL) {
    1092         265 :                         if (GDKsetenv("gdk_dbname", p + 1) != GDK_SUCCEED) {
    1093           0 :                                 TRC_CRITICAL(GDK, "GDKsetenv gdk_dbname failed");
    1094           0 :                                 return GDK_FAIL;
    1095             :                         }
    1096             : #if DIR_SEP != '/'              /* on Windows look for different separator */
    1097             :                 } else if ((p = GDKgetenv("gdk_dbpath")) != NULL &&
    1098             :                                    (p = strrchr(p, '/')) != NULL) {
    1099             :                         if (GDKsetenv("gdk_dbname", p + 1) != GDK_SUCCEED) {
    1100             :                                 TRC_CRITICAL(GDK, "GDKsetenv gdk_dbname failed");
    1101             :                                 return GDK_FAIL;
    1102             :                         }
    1103             : #endif
    1104             :                 }
    1105           1 :         } else if (GDKgetenv("gdk_dbname") == NULL) {
    1106           1 :                 if (GDKsetenv("gdk_dbname", "in-memory") != GDK_SUCCEED) {
    1107           0 :                         TRC_CRITICAL(GDK, "GDKsetenv gdk_dbname failed");
    1108           0 :                         return GDK_FAIL;
    1109             :                 }
    1110             :         }
    1111         266 :         if (GDKgetenv("gdk_vm_maxsize") == NULL) {
    1112         121 :                 snprintf(buf, sizeof(buf), "%zu", GDK_vm_maxsize);
    1113         121 :                 if (GDKsetenv("gdk_vm_maxsize", buf) != GDK_SUCCEED) {
    1114           0 :                         TRC_CRITICAL(GDK, "GDKsetenv gdk_vm_maxsize failed");
    1115           0 :                         return GDK_FAIL;
    1116             :                 }
    1117             :         }
    1118         266 :         if (GDKgetenv("gdk_mem_maxsize") == NULL) {
    1119         266 :                 snprintf(buf, sizeof(buf), "%zu", GDK_mem_maxsize);
    1120         266 :                 if (GDKsetenv("gdk_mem_maxsize", buf) != GDK_SUCCEED) {
    1121           0 :                         TRC_CRITICAL(GDK, "GDKsetenv gdk_mem_maxsize failed");
    1122           0 :                         return GDK_FAIL;
    1123             :                 }
    1124             :         }
    1125         266 :         if (GDKgetenv("gdk_mmap_minsize_persistent") == NULL) {
    1126         266 :                 snprintf(buf, sizeof(buf), "%zu", GDK_mmap_minsize_persistent);
    1127         266 :                 if (GDKsetenv("gdk_mmap_minsize_persistent", buf) != GDK_SUCCEED) {
    1128           0 :                         TRC_CRITICAL(GDK, "GDKsetenv gdk_mmap_minsize_persistent failed");
    1129           0 :                         return GDK_FAIL;
    1130             :                 }
    1131             :         }
    1132         266 :         if (GDKgetenv("gdk_mmap_minsize_transient") == NULL) {
    1133         266 :                 snprintf(buf, sizeof(buf), "%zu", GDK_mmap_minsize_transient);
    1134         266 :                 if (GDKsetenv("gdk_mmap_minsize_transient", buf) != GDK_SUCCEED) {
    1135           0 :                         TRC_CRITICAL(GDK, "GDKsetenv gdk_mmap_minsize_transient failed");
    1136           0 :                         return GDK_FAIL;
    1137             :                 }
    1138             :         }
    1139         266 :         if (GDKgetenv("gdk_mmap_pagesize") == NULL) {
    1140         266 :                 snprintf(buf, sizeof(buf), "%zu", GDK_mmap_pagesize);
    1141         266 :                 if (GDKsetenv("gdk_mmap_pagesize", buf) != GDK_SUCCEED) {
    1142           0 :                         TRC_CRITICAL(GDK, "GDKsetenv gdk_mmap_pagesize failed");
    1143           0 :                         return GDK_FAIL;
    1144             :                 }
    1145             :         }
    1146         266 :         if (GDKgetenv("monet_pid") == NULL) {
    1147         266 :                 snprintf(buf, sizeof(buf), "%d", (int) getpid());
    1148         266 :                 if (GDKsetenv("monet_pid", buf) != GDK_SUCCEED) {
    1149           0 :                         TRC_CRITICAL(GDK, "GDKsetenv monet_pid failed");
    1150           0 :                         return GDK_FAIL;
    1151             :                 }
    1152             :         }
    1153         266 :         if (GDKsetenv("revision", mercurial_revision()) != GDK_SUCCEED) {
    1154           0 :                 TRC_CRITICAL(GDK, "GDKsetenv revision failed");
    1155           0 :                 return GDK_FAIL;
    1156             :         }
    1157         266 :         GDK_UNIQUE_ESTIMATE_KEEP_FRACTION = 0;
    1158         266 :         if ((p = GDKgetenv("gdk_unique_estimate_keep_fraction")) != NULL)
    1159           0 :                 GDK_UNIQUE_ESTIMATE_KEEP_FRACTION = (BUN) strtoll(p, NULL, 10);
    1160         266 :         if (GDK_UNIQUE_ESTIMATE_KEEP_FRACTION == 0)
    1161         266 :                 GDK_UNIQUE_ESTIMATE_KEEP_FRACTION = 1000;
    1162         266 :         HASH_DESTROY_UNIQUES_FRACTION = 0;
    1163         266 :         if ((p = GDKgetenv("hash_destroy_uniques_fraction")) != NULL)
    1164           0 :                 HASH_DESTROY_UNIQUES_FRACTION = (BUN) strtoll(p, NULL, 10);
    1165         266 :         if (HASH_DESTROY_UNIQUES_FRACTION == 0)
    1166         266 :                 HASH_DESTROY_UNIQUES_FRACTION = GDK_UNIQUE_ESTIMATE_KEEP_FRACTION;
    1167         266 :         NO_HASH_SELECT_FRACTION = 0;
    1168         266 :         if ((p = GDKgetenv("no_hash_select_fraction")) != NULL)
    1169           0 :                 NO_HASH_SELECT_FRACTION = (dbl) strtoll(p, NULL, 10);
    1170         266 :         if (NO_HASH_SELECT_FRACTION == 0)
    1171         266 :                 NO_HASH_SELECT_FRACTION = (dbl) GDK_UNIQUE_ESTIMATE_KEEP_FRACTION;
    1172             : 
    1173             :         return GDK_SUCCEED;
    1174             : }
    1175             : 
    1176             : int GDKnr_threads = 0;
    1177             : static ATOMIC_TYPE GDKnrofthreads = ATOMIC_VAR_INIT(0);
    1178             : static struct threadStruct GDKthreads[THREADS];
    1179             : 
    1180             : bool
    1181      446357 : GDKexiting(void)
    1182             : {
    1183      446357 :         return (bool) (ATOMIC_GET(&GDKstopped) > 0);
    1184             : }
    1185             : 
    1186             : void
    1187         265 : GDKprepareExit(void)
    1188             : {
    1189         265 :         ATOMIC_ADD(&GDKstopped, 1);
    1190             : 
    1191         265 :         if (MT_getpid() == mainpid) {
    1192         264 :                 TRC_DEBUG_IF(THRD)
    1193           0 :                         dump_threads();
    1194         264 :                 join_detached_threads();
    1195             :         }
    1196         265 : }
    1197             : 
    1198             : void
    1199         264 : GDKreset(int status)
    1200             : {
    1201         264 :         MT_Id pid = MT_getpid();
    1202             : 
    1203         264 :         assert(GDKexiting());
    1204             : 
    1205         264 :         if (GDKkey) {
    1206         264 :                 BBPunfix(GDKkey->batCacheid);
    1207         264 :                 GDKkey = NULL;
    1208             :         }
    1209         264 :         if (GDKval) {
    1210         264 :                 BBPunfix(GDKval->batCacheid);
    1211         264 :                 GDKval = NULL;
    1212             :         }
    1213             : 
    1214         264 :         join_detached_threads();
    1215             : 
    1216         264 :         MT_lock_set(&GDKenvlock);
    1217         264 :         while (orig_value) {
    1218             :                 struct orig_value *ov = orig_value;
    1219           0 :                 orig_value = orig_value->next;
    1220           0 :                 GDKfree(ov);
    1221             :         }
    1222         264 :         MT_lock_unset(&GDKenvlock);
    1223             : 
    1224         264 :         if (status == 0) {
    1225             :                 /* they had their chance, now kill them */
    1226             :                 bool killed = false;
    1227         264 :                 MT_lock_set(&GDKthreadLock);
    1228      270600 :                 for (Thread t = GDKthreads; t < GDKthreads + THREADS; t++) {
    1229             :                         MT_Id victim;
    1230      270336 :                         if ((victim = (MT_Id) ATOMIC_GET(&t->pid)) != 0) {
    1231         264 :                                 if (pid && victim != pid) {
    1232             :                                         int e;
    1233             : 
    1234             :                                         killed = true;
    1235           0 :                                         e = MT_kill_thread(victim);
    1236           0 :                                         TRC_INFO(GDK, "Killing thread: %d\n", e);
    1237           0 :                                         (void) ATOMIC_DEC(&GDKnrofthreads);
    1238             :                                 }
    1239         264 :                                 ATOMIC_SET(&t->pid, 0);
    1240             :                         }
    1241             :                 }
    1242         264 :                 assert(ATOMIC_GET(&GDKnrofthreads) <= 1);
    1243             :                 /* all threads ceased running, now we can clean up */
    1244         264 :                 if (!killed) {
    1245             :                         /* we can't clean up after killing threads */
    1246         264 :                         BBPexit();
    1247             :                 }
    1248         264 :                 GDKlog(GET_GDKLOCK(PERSISTENT), GDKLOGOFF);
    1249             : 
    1250        8712 :                 for (int farmid = 0; farmid < MAXFARMS; farmid++) {
    1251        8448 :                         if (BBPfarms[farmid].dirname != NULL) {
    1252             :                                 bool skip = false;
    1253         769 :                                 for (int j = 0; j < farmid; j++) {
    1254         253 :                                         if (BBPfarms[j].dirname != NULL &&
    1255           0 :                                             strcmp(BBPfarms[farmid].dirname, BBPfarms[j].dirname) == 0) {
    1256             :                                                 skip = true;
    1257             :                                                 break;
    1258             :                                         }
    1259             :                                 }
    1260         516 :                                 if (!skip)
    1261         516 :                                         GDKunlockHome(farmid);
    1262         516 :                                 if (BBPfarms[farmid].dirname) {
    1263         516 :                                         GDKfree((char*)BBPfarms[farmid].dirname);
    1264         516 :                                         BBPfarms[farmid].dirname = NULL;
    1265             :                                 }
    1266             :                         }
    1267             :                 }
    1268             : 
    1269             : #ifdef LOCK_STATS
    1270             :                 TRC_DEBUG_IF(TEM) GDKlockstatistics(1);
    1271             : #endif
    1272         264 :                 GDKdebug = 0;
    1273         264 :                 GDK_mmap_minsize_persistent = MMAP_MINSIZE_PERSISTENT;
    1274         264 :                 GDK_mmap_minsize_transient = MMAP_MINSIZE_TRANSIENT;
    1275         264 :                 GDK_mmap_pagesize = MMAP_PAGESIZE;
    1276         264 :                 GDK_mem_maxsize = (size_t) ((double) MT_npages() * (double) MT_pagesize() * 0.815);
    1277         264 :                 GDK_vm_maxsize = GDK_VM_MAXSIZE;
    1278         264 :                 GDKatomcnt = TYPE_str + 1;
    1279             : 
    1280         264 :                 if (GDK_mem_maxsize / 16 < GDK_mmap_minsize_transient) {
    1281         264 :                         GDK_mmap_minsize_transient = GDK_mem_maxsize / 16;
    1282         264 :                         if (GDK_mmap_minsize_persistent > GDK_mmap_minsize_transient)
    1283           0 :                                 GDK_mmap_minsize_persistent = GDK_mmap_minsize_transient;
    1284             :                 }
    1285             : 
    1286         264 :                 GDKnr_threads = 0;
    1287         264 :                 ATOMIC_SET(&GDKnrofthreads, 0);
    1288         264 :                 close_stream((stream *) THRdata[0]);
    1289         264 :                 close_stream((stream *) THRdata[1]);
    1290             : 
    1291         264 :                 memset(THRdata, 0, sizeof(THRdata));
    1292         264 :                 gdk_bbp_reset();
    1293         264 :                 MT_lock_unset(&GDKthreadLock);
    1294             :         }
    1295         264 :         ATOMunknown_clean();
    1296             : 
    1297             :         /* stop GDKtracer */
    1298         264 :         GDKtracer_stop();
    1299         264 : }
    1300             : 
    1301             : /* coverity[+kill] */
    1302             : void
    1303           0 : GDKexit(int status)
    1304             : {
    1305           0 :         if (!GDKinmemory(0) && GET_GDKLOCK(PERSISTENT) == NULL) {
    1306             :                 /* stop GDKtracer */
    1307           0 :                 GDKtracer_stop();
    1308             : 
    1309             :                 /* no database lock, so no threads, so exit now */
    1310           0 :                 if (!GDKembedded())
    1311           0 :                         exit(status);
    1312             :         }
    1313           0 :         GDKprepareExit();
    1314           0 :         GDKreset(status);
    1315           0 :         if (!GDKembedded())
    1316           0 :                 exit(status);
    1317           0 : }
    1318             : 
    1319             : /*
    1320             :  * All semaphores used by the application should be mentioned here.
    1321             :  * They are initialized during system initialization.
    1322             :  */
    1323             : 
    1324             : batlock_t GDKbatLock[BBP_BATMASK + 1];
    1325             : MT_Lock GDKthreadLock = MT_LOCK_INITIALIZER(GDKthreadLock);
    1326             : 
    1327             : /* GDKtmLock protects all accesses and changes to BAKDIR and SUBDIR */
    1328             : MT_Lock GDKtmLock = MT_LOCK_INITIALIZER(GDKtmLock);
    1329             : 
    1330             : /*
    1331             :  * @+ Concurrency control
    1332             :  * Concurrency control requires actions at several levels of the
    1333             :  * system.  First, it should be ensured that each database is
    1334             :  * controlled by a single server process (group). Subsequent attempts
    1335             :  * should be stopped.  This is regulated through file locking against
    1336             :  * ".gdk_lock".
    1337             :  *
    1338             :  * Before the locks and threads are initiated, we cannot use the
    1339             :  * normal routines yet. So we have a local fatal here instead of
    1340             :  * GDKfatal.
    1341             :  */
    1342             : static gdk_return
    1343         412 : GDKlockHome(int farmid)
    1344             : {
    1345             :         int fd;
    1346             :         struct stat st;
    1347             :         char *gdklockpath;
    1348             :         FILE *GDKlockFile;
    1349             : 
    1350         412 :         assert(BBPfarms[farmid].dirname != NULL);
    1351         412 :         assert(BBPfarms[farmid].lock_file == NULL);
    1352             : 
    1353         412 :         if ((gdklockpath = GDKfilepath(farmid, NULL, GDKLOCK, NULL)) == NULL) {
    1354             :                 return GDK_FAIL;
    1355             :         }
    1356             : 
    1357             :         /*
    1358             :          * Obtain the global database lock.
    1359             :          */
    1360         412 :         if (MT_stat(BBPfarms[farmid].dirname, &st) < 0 &&
    1361           0 :             GDKcreatedir(gdklockpath) != GDK_SUCCEED) {
    1362           0 :                 TRC_CRITICAL(GDK, "could not create %s\n",
    1363             :                          BBPfarms[farmid].dirname);
    1364           0 :                 GDKfree(gdklockpath);
    1365           0 :                 return GDK_FAIL;
    1366             :         }
    1367         412 :         if ((fd = MT_lockf(gdklockpath, F_TLOCK)) < 0) {
    1368           2 :                 TRC_CRITICAL(GDK, "Database lock '%s' denied\n",
    1369             :                          gdklockpath);
    1370           2 :                 GDKfree(gdklockpath);
    1371           2 :                 return GDK_FAIL;
    1372             :         }
    1373             : 
    1374             :         /* now we have the lock on the database and are the only
    1375             :          * process allowed in this section */
    1376             : 
    1377         410 :         if ((GDKlockFile = fdopen(fd, "r+")) == NULL) {
    1378           0 :                 GDKsyserror("Could not fdopen %s\n", gdklockpath);
    1379           0 :                 close(fd);
    1380           0 :                 GDKfree(gdklockpath);
    1381             :                 return GDK_FAIL;
    1382             :         }
    1383             : 
    1384             :         /*
    1385             :          * Print the new process list in the global lock file.
    1386             :          */
    1387         410 :         if (fseek(GDKlockFile, 0, SEEK_SET) == -1) {
    1388           0 :                 fclose(GDKlockFile);
    1389           0 :                 TRC_CRITICAL(GDK, "Error while setting the file pointer on %s\n", gdklockpath);
    1390           0 :                 GDKfree(gdklockpath);
    1391           0 :                 return GDK_FAIL;
    1392             :         }
    1393         410 :         if (ftruncate(fileno(GDKlockFile), 0) < 0) {
    1394           0 :                 fclose(GDKlockFile);
    1395           0 :                 TRC_CRITICAL(GDK, "Could not truncate %s\n", gdklockpath);
    1396           0 :                 GDKfree(gdklockpath);
    1397           0 :                 return GDK_FAIL;
    1398             :         }
    1399         410 :         if (fflush(GDKlockFile) == EOF) {
    1400           0 :                 fclose(GDKlockFile);
    1401           0 :                 TRC_CRITICAL(GDK, "Could not flush %s\n", gdklockpath);
    1402           0 :                 GDKfree(gdklockpath);
    1403           0 :                 return GDK_FAIL;
    1404             :         }
    1405         410 :         GDKlog(GDKlockFile, GDKLOGON);
    1406         410 :         GDKfree(gdklockpath);
    1407         410 :         BBPfarms[farmid].lock_file = GDKlockFile;
    1408         410 :         return GDK_SUCCEED;
    1409             : }
    1410             : 
    1411             : 
    1412             : static void
    1413         516 : GDKunlockHome(int farmid)
    1414             : {
    1415         516 :         if (BBPfarms[farmid].lock_file) {
    1416         408 :                 char *gdklockpath = GDKfilepath(farmid, NULL, GDKLOCK, NULL);
    1417         408 :                 if (gdklockpath)
    1418         408 :                         MT_lockf(gdklockpath, F_ULOCK);
    1419         408 :                 fclose(BBPfarms[farmid].lock_file);
    1420         408 :                 BBPfarms[farmid].lock_file = NULL;
    1421         408 :                 GDKfree(gdklockpath);
    1422             :         }
    1423         516 : }
    1424             : 
    1425             : /*
    1426             :  * @+ Error handling
    1427             :  * Errors come in three flavors: warnings, non-fatal and fatal errors.
    1428             :  * A fatal error leaves a core dump behind after trying to safe the
    1429             :  * content of the relation.  A non-fatal error returns a message to
    1430             :  * the user and aborts the current transaction.  Fatal errors are also
    1431             :  * recorded on the system log for post-mortem analysis.
    1432             :  * In non-silent mode the errors are immediately sent to output, which
    1433             :  * makes it hard for upper layers to detect if an error was produced
    1434             :  * in the process. To facilitate such testing, a global error count is
    1435             :  * maintained on a thread basis, which can be read out by the function
    1436             :  * GDKerrorCount(); Furthermore, threads may have set their private
    1437             :  * error buffer.
    1438             :  */
    1439             : 
    1440             : #define GDKERRLEN       (1024+512)
    1441             : 
    1442             : void
    1443    13669521 : GDKclrerr(void)
    1444             : {
    1445             :         char *buf;
    1446             : 
    1447    13669521 :         buf = GDKerrbuf;
    1448    13667568 :         if (buf)
    1449    13650616 :                 *buf = 0;
    1450    13667568 : }
    1451             : 
    1452             : jmp_buf GDKfataljump;
    1453             : str GDKfatalmsg;
    1454             : bit GDKfataljumpenable = 0;
    1455             : 
    1456             : /* coverity[+kill] */
    1457             : void
    1458           0 : GDKfatal(const char *format, ...)
    1459             : {
    1460             :         char message[GDKERRLEN];
    1461             :         size_t len = strlen(GDKFATAL);
    1462             :         va_list ap;
    1463             : 
    1464           0 :         GDKtracer_set_component_level("io", "debug");
    1465             : #ifndef NATIVE_WIN32
    1466             :         BATSIGinit();
    1467             : #endif
    1468           0 :         if (!strncmp(format, GDKFATAL, len)) {
    1469             :                 len = 0;
    1470             :         } else {
    1471           0 :                 strcpy(message, GDKFATAL);
    1472             :         }
    1473           0 :         va_start(ap, format);
    1474           0 :         vsnprintf(message + len, sizeof(message) - (len + 2), format, ap);
    1475           0 :         va_end(ap);
    1476             : 
    1477             : #ifndef __COVERITY__
    1478           0 :         if (GDKfataljumpenable) {
    1479             :                 // in embedded mode, we really don't want to kill our host
    1480           0 :                 GDKfatalmsg = GDKstrdup(message);
    1481           0 :                 longjmp(GDKfataljump, 42);
    1482             :         } else
    1483             : #endif
    1484             :         {
    1485           0 :                 fputs(message, stderr);
    1486           0 :                 fputs("\n", stderr);
    1487           0 :                 fflush(stderr);
    1488             : 
    1489             :                 /*
    1490             :                  * Real errors should be saved in the log file for post-crash
    1491             :                  * inspection.
    1492             :                  */
    1493           0 :                 if (GDKexiting()) {
    1494           0 :                         fflush(stdout);
    1495           0 :                         exit(1);
    1496             :                 } else {
    1497           0 :                         GDKlog(GET_GDKLOCK(PERSISTENT), "%s", message);
    1498             : #ifdef COREDUMP
    1499             :                         abort();
    1500             : #else
    1501           0 :                         exit(1);
    1502             : #endif
    1503             :                 }
    1504             :         }
    1505             : }
    1506             : 
    1507             : 
    1508             : lng
    1509   149131127 : GDKusec(void)
    1510             : {
    1511             :         /* Return the time in microseconds since an epoch.  The epoch
    1512             :          * is currently midnight at the start of January 1, 1970, UTC. */
    1513             : #if defined(NATIVE_WIN32)
    1514             :         FILETIME ft;
    1515             :         ULARGE_INTEGER f;
    1516             :         GetSystemTimeAsFileTime(&ft); /* time since Jan 1, 1601 */
    1517             :         f.LowPart = ft.dwLowDateTime;
    1518             :         f.HighPart = ft.dwHighDateTime;
    1519             :         /* there are 369 years, of which 89 are leap years from
    1520             :          * January 1, 1601 to January 1, 1970 which makes 134774 days;
    1521             :          * multiply that with the number of seconds in a day and the
    1522             :          * number of 100ns units in a second; subtract that from the
    1523             :          * value for the current time since January 1, 1601 to get the
    1524             :          * time since the Unix epoch */
    1525             :         f.QuadPart -= LL_CONSTANT(134774) * 24 * 60 * 60 * 10000000;
    1526             :         /* and convert to microseconds */
    1527             :         return (lng) (f.QuadPart / 10);
    1528             : #elif defined(HAVE_CLOCK_GETTIME)
    1529             :         struct timespec ts;
    1530   149131127 :         (void) clock_gettime(CLOCK_REALTIME, &ts);
    1531   149344258 :         return (lng) (ts.tv_sec * LL_CONSTANT(1000000) + ts.tv_nsec / 1000);
    1532             : #elif defined(HAVE_GETTIMEOFDAY)
    1533             :         struct timeval tv;
    1534             :         gettimeofday(&tv, NULL);
    1535             :         return (lng) (tv.tv_sec * LL_CONSTANT(1000000) + tv.tv_usec);
    1536             : #elif defined(HAVE_FTIME)
    1537             :         struct timeb tb;
    1538             :         ftime(&tb);
    1539             :         return (lng) (tb.time * LL_CONSTANT(1000000) + tb.millitm * LL_CONSTANT(1000));
    1540             : #else
    1541             :         /* last resort */
    1542             :         return (lng) (time(NULL) * LL_CONSTANT(1000000));
    1543             : #endif
    1544             : }
    1545             : 
    1546             : 
    1547             : int
    1548      213445 : GDKms(void)
    1549             : {
    1550             :         /* wraps around after a bit over 24 days */
    1551      213445 :         return (int) ((GDKusec() - programepoch) / 1000);
    1552             : }
    1553             : 
    1554             : 
    1555             : /*
    1556             :  * @+ Logical Thread management
    1557             :  *
    1558             :  * All semaphores used by the application should be mentioned here.
    1559             :  * They are initialized during system initialization.
    1560             :  *
    1561             :  * The first action upon thread creation is to add it to the pool of
    1562             :  * known threads. This should be done by the thread itself.
    1563             :  * Subsequently, the thread descriptor can be obtained using THRget.
    1564             :  * Note that the users should have gained exclusive access already.  A
    1565             :  * new entry is initialized automatically when not found.  Its file
    1566             :  * descriptors are the same as for the server and should be
    1567             :  * subsequently reset.
    1568             :  */
    1569             : void *THRdata[THREADDATA] = { 0 };
    1570             : 
    1571             : Thread
    1572           0 : THRget(int tid)
    1573             : {
    1574           0 :         assert(0 < tid && tid <= THREADS);
    1575           0 :         return &GDKthreads[tid - 1];
    1576             : }
    1577             : 
    1578             : #if defined(_MSC_VER) && _MSC_VER >= 1900
    1579             : #pragma warning(disable : 4172)
    1580             : #endif
    1581             : static inline uintptr_t
    1582             : THRsp(void)
    1583             : {
    1584             :         int l = 0;
    1585    65683763 :         uintptr_t sp = (uintptr_t) (&l);
    1586             : 
    1587             :         return sp;
    1588             : }
    1589             : 
    1590             : static inline Thread
    1591             : GDK_find_self(void)
    1592             : {
    1593   195194567 :         return (Thread) MT_thread_getdata();
    1594             : }
    1595             : 
    1596             : static Thread
    1597      136067 : THRnew(const char *name, MT_Id pid)
    1598             : {
    1599      992896 :         for (Thread s = GDKthreads; s < GDKthreads + THREADS; s++) {
    1600             :                 ATOMIC_BASE_TYPE npid = 0;
    1601      992896 :                 if (ATOMIC_CAS(&s->pid, &npid, pid)) {
    1602             :                         /* successfully allocated, fill in rest */
    1603      136067 :                         s->data[0] = THRdata[0];
    1604      136067 :                         s->data[1] = THRdata[1];
    1605      136067 :                         s->sp = THRsp();
    1606      136067 :                         strcpy_len(s->name, name, sizeof(s->name));
    1607      136067 :                         TRC_DEBUG(PAR, "%x %zu sp = %zu\n",
    1608             :                                   (unsigned) s->tid,
    1609             :                                   (size_t) ATOMIC_GET(&s->pid),
    1610             :                                   (size_t) s->sp);
    1611      136067 :                         TRC_DEBUG(PAR, "Number of threads: %d\n",
    1612             :                                   (int) ATOMIC_GET(&GDKnrofthreads) + 1);
    1613             :                         return s;
    1614             :                 }
    1615             :         }
    1616           0 :         TRC_DEBUG(IO_, "Too many threads\n");
    1617           0 :         GDKerror("too many threads\n");
    1618           0 :         return NULL;
    1619             : }
    1620             : 
    1621             : struct THRstart {
    1622             :         void (*func) (void *);
    1623             :         void *arg;
    1624             :         MT_Sema sem;
    1625             :         Thread thr;
    1626             : };
    1627             : 
    1628             : static void
    1629      135798 : THRstarter(void *a)
    1630             : {
    1631             :         struct THRstart *t = a;
    1632      135798 :         void (*func) (void *) = t->func;
    1633      135798 :         void *arg = t->arg;
    1634             : 
    1635      135798 :         MT_sema_down(&t->sem);
    1636      135799 :         t->thr->sp = THRsp();
    1637      135799 :         MT_thread_setdata(t->thr);
    1638      135799 :         (*func)(arg);
    1639      135779 :         THRdel(t->thr);
    1640      135786 :         MT_sema_destroy(&t->sem);
    1641      135774 :         GDKfree(a);
    1642      135788 : }
    1643             : 
    1644             : MT_Id
    1645      135799 : THRcreate(void (*f) (void *), void *arg, enum MT_thr_detach d, const char *name)
    1646             : {
    1647             :         MT_Id pid;
    1648             :         Thread s;
    1649             :         struct THRstart *t;
    1650             :         static ATOMIC_TYPE ctr = ATOMIC_VAR_INIT(0);
    1651             :         char semname[32];
    1652             :         int len;
    1653             : 
    1654      135799 :         if ((t = GDKmalloc(sizeof(*t))) == NULL)
    1655             :                 return 0;
    1656      135799 :         if ((s = THRnew(name, ~(MT_Id)0)) == NULL) {
    1657           0 :                 GDKfree(t);
    1658           0 :                 return 0;
    1659             :         }
    1660      135799 :         *t = (struct THRstart) {
    1661             :                 .func = f,
    1662             :                 .arg = arg,
    1663             :                 .thr = s,
    1664             :         };
    1665      135799 :         len = snprintf(semname, sizeof(semname), "THRcreate%" PRIu64, (uint64_t) ATOMIC_INC(&ctr));
    1666      135799 :         if (len == -1 || len > (int) sizeof(semname)) {
    1667           0 :                 TRC_WARNING(IO_, "Semaphore name is too large\n");
    1668             :         }
    1669      135799 :         MT_sema_init(&t->sem, 0, semname);
    1670      135799 :         if (MT_create_thread(&pid, THRstarter, t, d, name) != 0) {
    1671           0 :                 GDKerror("could not start thread\n");
    1672           0 :                 MT_sema_destroy(&t->sem);
    1673           0 :                 GDKfree(t);
    1674           0 :                 ATOMIC_SET(&s->pid, 0); /* deallocate */
    1675           0 :                 return 0;
    1676             :         }
    1677             :         /* must not fail after this: the thread has been started */
    1678      135799 :         (void) ATOMIC_INC(&GDKnrofthreads);
    1679      135799 :         ATOMIC_SET(&s->pid, pid);
    1680             :         /* send new thread on its way */
    1681      135799 :         MT_sema_up(&t->sem);
    1682      135799 :         return pid;
    1683             : }
    1684             : 
    1685             : void
    1686      135775 : THRdel(Thread t)
    1687             : {
    1688      135775 :         assert(GDKthreads <= t && t < GDKthreads + THREADS);
    1689      135775 :         MT_thread_setdata(NULL);
    1690      135771 :         TRC_DEBUG(PAR, "pid = %zu, disconnected, %d left\n",
    1691             :                   (size_t) ATOMIC_GET(&t->pid),
    1692             :                   (int) ATOMIC_GET(&GDKnrofthreads));
    1693             : 
    1694      135771 :         t->name[0] = 0;
    1695      543087 :         for (int i = 0; i < THREADDATA; i++)
    1696      407316 :                 t->data[i] = NULL;
    1697      135771 :         t->sp = 0;
    1698      135771 :         ATOMIC_SET(&t->pid, 0);  /* deallocate */
    1699      135771 :         (void) ATOMIC_DEC(&GDKnrofthreads);
    1700      135771 : }
    1701             : 
    1702             : int
    1703    65411879 : THRhighwater(void)
    1704             : {
    1705             :         uintptr_t c;
    1706             :         Thread s;
    1707             :         size_t diff;
    1708             :         int rc = 0;
    1709             : 
    1710             :         s = GDK_find_self();
    1711    65411897 :         if (s != NULL) {
    1712             :                 c = THRsp();
    1713    65411897 :                 diff = c < s->sp ? s->sp - c : c - s->sp;
    1714    65411897 :                 if (diff > THREAD_STACK_SIZE - 80 * 1024)
    1715             :                         rc = 1;
    1716             :         }
    1717    65411897 :         return rc;
    1718             : }
    1719             : 
    1720             : /*
    1721             :  * I/O is organized per thread, because users may gain access through
    1722             :  * the network.  The code below should be improved to gain speed.
    1723             :  */
    1724             : 
    1725             : static int
    1726         268 : THRinit(void)
    1727             : {
    1728             :         int i = 0;
    1729             :         Thread s;
    1730             :         static bool first = true;
    1731             : 
    1732         268 :         if ((THRdata[0] = (void *) stdout_wastream()) == NULL) {
    1733           0 :                 TRC_CRITICAL(GDK, "malloc for stdout failed\n");
    1734           0 :                 return -1;
    1735             :         }
    1736         268 :         if ((THRdata[1] = (void *) stdin_rastream()) == NULL) {
    1737           0 :                 TRC_CRITICAL(GDK, "malloc for stdin failed\n");
    1738           0 :                 mnstr_destroy(THRdata[0]);
    1739           0 :                 THRdata[0] = NULL;
    1740           0 :                 return -1;
    1741             :         }
    1742         268 :         if (first) {
    1743      264450 :                 for (i = 0; i < THREADS; i++) {
    1744      264192 :                         GDKthreads[i].tid = i + 1;
    1745      264192 :                         ATOMIC_INIT(&GDKthreads[i].pid, 0);
    1746             :                 }
    1747         258 :                 first = false;
    1748             :         }
    1749         268 :         if ((s = THRnew("main thread", MT_getpid())) == NULL) {
    1750           0 :                 TRC_CRITICAL(GDK, "THRnew failed\n");
    1751           0 :                 mnstr_destroy(THRdata[0]);
    1752           0 :                 THRdata[0] = NULL;
    1753           0 :                 mnstr_destroy(THRdata[1]);
    1754           0 :                 THRdata[1] = NULL;
    1755           0 :                 return -1;
    1756             :         }
    1757         268 :         (void) ATOMIC_INC(&GDKnrofthreads);
    1758         268 :         MT_thread_setdata(s);
    1759         268 :         return 0;
    1760             : }
    1761             : 
    1762             : void
    1763      268774 : THRsetdata(int n, ptr val)
    1764             : {
    1765             :         Thread s;
    1766             : 
    1767             :         s = GDK_find_self();
    1768      268782 :         if (s) {
    1769      268782 :                 assert(val == NULL || s->data[n] == NULL);
    1770      268782 :                 s->data[n] = val;
    1771             :         }
    1772      268782 : }
    1773             : 
    1774             : void *
    1775    30868304 : THRgetdata(int n)
    1776             : {
    1777             :         Thread s;
    1778             :         void *d;
    1779             : 
    1780             :         s = GDK_find_self();
    1781    30893572 :         d = s ? s->data[n] : THRdata[n];
    1782    30893572 :         return d;
    1783             : }
    1784             : 
    1785             : int
    1786    98645610 : THRgettid(void)
    1787             : {
    1788             :         Thread s;
    1789             :         int t;
    1790             : 
    1791             :         s = GDK_find_self();
    1792    98649901 :         t = s ? s->tid : 1;
    1793    98649901 :         return t;
    1794             : }
    1795             : 
    1796             : const char *
    1797         255 : GDKversion(void)
    1798             : {
    1799         255 :         return MONETDB_VERSION;
    1800             : }
    1801             : 
    1802             : const char *
    1803         521 : GDKlibversion(void)
    1804             : {
    1805         521 :         return GDK_VERSION;
    1806             : }
    1807             : 
    1808             : inline size_t
    1809     8888352 : GDKmem_cursize(void)
    1810             : {
    1811             :         /* RAM/swapmem that Monet is really using now */
    1812   648599310 :         return (size_t) ATOMIC_GET(&GDK_mallocedbytes_estimate);
    1813             : }
    1814             : 
    1815             : inline size_t
    1816   639710958 : GDKvm_cursize(void)
    1817             : {
    1818             :         /* current Monet VM address space usage */
    1819   639710958 :         return (size_t) ATOMIC_GET(&GDK_vm_cursize) + GDKmem_cursize();
    1820             : }
    1821             : 
    1822             : #define heapinc(_memdelta)                                              \
    1823             :         (void) ATOMIC_ADD(&GDK_mallocedbytes_estimate, _memdelta)
    1824             : #define heapdec(_memdelta)                                              \
    1825             :         (void) ATOMIC_SUB(&GDK_mallocedbytes_estimate, _memdelta)
    1826             : 
    1827             : #define meminc(vmdelta)                                                 \
    1828             :         (void) ATOMIC_ADD(&GDK_vm_cursize, (ssize_t) SEG_SIZE((vmdelta), MT_VMUNITLOG))
    1829             : #define memdec(vmdelta)                                                 \
    1830             :         (void) ATOMIC_SUB(&GDK_vm_cursize, (ssize_t) SEG_SIZE((vmdelta), MT_VMUNITLOG))
    1831             : 
    1832             : /* Memory allocation
    1833             :  *
    1834             :  * The functions GDKmalloc, GDKzalloc, GDKrealloc, GDKstrdup, and
    1835             :  * GDKfree are used throughout to allocate and free memory.  These
    1836             :  * functions are almost directly mapped onto the system
    1837             :  * malloc/realloc/free functions, but they give us some extra
    1838             :  * debugging hooks.
    1839             :  *
    1840             :  * When allocating memory, we allocate a bit more than was asked for.
    1841             :  * The extra space is added onto the front of the memory area that is
    1842             :  * returned, and in debug builds also some at the end.  The area in
    1843             :  * front is used to store the actual size of the allocated area.  The
    1844             :  * most important use is to be able to keep statistics on how much
    1845             :  * memory is being used.  In debug builds, the size is also used to
    1846             :  * make sure that we don't write outside of the allocated arena.  This
    1847             :  * is also where the extra space at the end comes in.
    1848             :  */
    1849             : 
    1850             : /* we allocate extra space and return a pointer offset by this amount */
    1851             : #define MALLOC_EXTRA_SPACE      (2 * SIZEOF_VOID_P)
    1852             : 
    1853             : #ifdef NDEBUG
    1854             : #define DEBUG_SPACE     0
    1855             : #else
    1856             : #define DEBUG_SPACE     16
    1857             : #endif
    1858             : 
    1859             : static void *
    1860   292162254 : GDKmalloc_internal(size_t size)
    1861             : {
    1862             :         void *s;
    1863             :         size_t nsize;
    1864             : 
    1865   292162254 :         assert(size != 0);
    1866             : #ifndef NDEBUG
    1867             :         /* fail malloc for testing purposes depending on set limit */
    1868   292162254 :         if (GDK_malloc_success_count > 0) {
    1869           0 :                 MT_lock_set(&mallocsuccesslock);
    1870           0 :                 if (GDK_malloc_success_count > 0)
    1871           0 :                         GDK_malloc_success_count--;
    1872           0 :                 MT_lock_unset(&mallocsuccesslock);
    1873             :         }
    1874   292162254 :         if (GDK_malloc_success_count == 0) {
    1875           0 :                 GDKerror("allocation failed because of testing limit\n");
    1876           0 :                 return NULL;
    1877             :         }
    1878             : #endif
    1879   292162254 :         if (GDKvm_cursize() + size >= GDK_vm_maxsize &&
    1880           0 :             !MT_thread_override_limits()) {
    1881           0 :                 GDKerror("allocating too much memory\n");
    1882           0 :                 return NULL;
    1883             :         }
    1884             : 
    1885             :         /* pad to multiple of eight bytes and add some extra space to
    1886             :          * write real size in front; when debugging, also allocate
    1887             :          * extra space for check bytes */
    1888   292868986 :         nsize = (size + 7) & ~7;
    1889   292868986 :         if ((s = malloc(nsize + MALLOC_EXTRA_SPACE + DEBUG_SPACE)) == NULL) {
    1890           0 :                 GDKsyserror("malloc failed; memory requested: %zu, memory in use: %zu, virtual memory in use: %zu\n", size, GDKmem_cursize(), GDKvm_cursize());;
    1891             :                 return NULL;
    1892             :         }
    1893   292868986 :         s = (void *) ((char *) s + MALLOC_EXTRA_SPACE);
    1894             : 
    1895   292868986 :         heapinc(nsize + MALLOC_EXTRA_SPACE + DEBUG_SPACE);
    1896             : 
    1897             :         /* just before the pointer that we return, write how much we
    1898             :          * asked of malloc */
    1899   292868986 :         ((size_t *) s)[-1] = nsize + MALLOC_EXTRA_SPACE + DEBUG_SPACE;
    1900             : #ifndef NDEBUG
    1901             :         /* just before that, write how much was asked of us */
    1902   292868986 :         ((size_t *) s)[-2] = size;
    1903             :         /* write pattern to help find out-of-bounds writes */
    1904   292868986 :         memset((char *) s + size, '\xBD', nsize + DEBUG_SPACE - size);
    1905             : #endif
    1906   292868986 :         return s;
    1907             : }
    1908             : 
    1909             : #undef GDKmalloc
    1910             : void *
    1911   161573232 : GDKmalloc(size_t size)
    1912             : {
    1913             :         void *s;
    1914             : 
    1915   161573232 :         if ((s = GDKmalloc_internal(size)) == NULL)
    1916             :                 return NULL;
    1917             : #ifndef NDEBUG
    1918             :         /* write a pattern to help make sure all data is properly
    1919             :          * initialized by the caller */
    1920   162492731 :         DEADBEEFCHK memset(s, '\xBD', size);
    1921             : #endif
    1922             :         return s;
    1923             : }
    1924             : 
    1925             : #undef GDKzalloc
    1926             : void *
    1927    69583652 : GDKzalloc(size_t size)
    1928             : {
    1929             :         void *s;
    1930             : 
    1931    69583652 :         if ((s = GDKmalloc_internal(size)) == NULL)
    1932             :                 return NULL;
    1933    69586530 :         memset(s, 0, size);
    1934    69586530 :         return s;
    1935             : }
    1936             : 
    1937             : #undef GDKstrdup
    1938             : char *
    1939    61253737 : GDKstrdup(const char *s)
    1940             : {
    1941             :         size_t size;
    1942             :         char *p;
    1943             : 
    1944    61253737 :         if (s == NULL)
    1945             :                 return NULL;
    1946    61252192 :         size = strlen(s) + 1;
    1947             : 
    1948    61252192 :         if ((p = GDKmalloc_internal(size)) == NULL)
    1949             :                 return NULL;
    1950    61270507 :         memcpy(p, s, size);     /* including terminating NULL byte */
    1951    61270507 :         return p;
    1952             : }
    1953             : 
    1954             : #undef GDKstrndup
    1955             : char *
    1956           0 : GDKstrndup(const char *s, size_t size)
    1957             : {
    1958             :         char *p;
    1959             : 
    1960           0 :         if (s == NULL)
    1961             :                 return NULL;
    1962           0 :         if ((p = GDKmalloc_internal(size + 1)) == NULL)
    1963             :                 return NULL;
    1964           0 :         if (size > 0)
    1965           0 :                 memcpy(p, s, size);
    1966           0 :         p[size] = '\0';         /* make sure it's NULL terminated */
    1967           0 :         return p;
    1968             : }
    1969             : 
    1970             : #undef GDKfree
    1971             : void
    1972   324381956 : GDKfree(void *s)
    1973             : {
    1974             :         size_t asize;
    1975             : 
    1976   324381956 :         if (s == NULL)
    1977             :                 return;
    1978             : 
    1979   292841185 :         asize = ((size_t *) s)[-1]; /* how much allocated last */
    1980             : 
    1981             : #ifndef NDEBUG
    1982   292841185 :         assert((asize & 2) == 0);   /* check against duplicate free */
    1983             :         /* check for out-of-bounds writes */
    1984             :         {
    1985   292841185 :                 size_t i = ((size_t *) s)[-2]; /* how much asked for last */
    1986  5744225541 :                 for (; i < asize - MALLOC_EXTRA_SPACE; i++)
    1987  5451384356 :                         assert(((char *) s)[i] == '\xBD');
    1988             :         }
    1989   292841185 :         ((size_t *) s)[-1] |= 2; /* indicate area is freed */
    1990             : #endif
    1991             : 
    1992             : #ifndef NDEBUG
    1993             :         /* overwrite memory that is to be freed with a pattern that
    1994             :          * will help us recognize access to already freed memory in
    1995             :          * the debugger */
    1996   292841185 :         DEADBEEFCHK memset(s, '\xDB', asize - MALLOC_EXTRA_SPACE);
    1997             : #endif
    1998             : 
    1999   292841185 :         free((char *) s - MALLOC_EXTRA_SPACE);
    2000   292841185 :         heapdec((ssize_t) asize);
    2001             : }
    2002             : 
    2003             : #undef GDKrealloc
    2004             : void *
    2005     4179123 : GDKrealloc(void *s, size_t size)
    2006             : {
    2007             :         size_t nsize, asize;
    2008             : #ifndef NDEBUG
    2009             :         size_t osize;
    2010             :         size_t *os;
    2011             : #endif
    2012             : 
    2013     4179123 :         assert(size != 0);
    2014             : 
    2015     4179123 :         if (s == NULL)
    2016           0 :                 return GDKmalloc(size);
    2017             : 
    2018     4179123 :         nsize = (size + 7) & ~7;
    2019     4179123 :         asize = ((size_t *) s)[-1]; /* how much allocated last */
    2020             : 
    2021     4179123 :         if (nsize > asize &&
    2022      987921 :             GDKvm_cursize() + nsize - asize >= GDK_vm_maxsize &&
    2023           0 :             !MT_thread_override_limits()) {
    2024           0 :                 GDKerror("allocating too much memory\n");
    2025           0 :                 return NULL;
    2026             :         }
    2027             : #ifndef NDEBUG
    2028     4179157 :         assert((asize & 2) == 0);   /* check against duplicate free */
    2029             :         /* check for out-of-bounds writes */
    2030     4179157 :         osize = ((size_t *) s)[-2]; /* how much asked for last */
    2031             :         {
    2032             :                 size_t i;
    2033    71181607 :                 for (i = osize; i < asize - MALLOC_EXTRA_SPACE; i++)
    2034    67002450 :                         assert(((char *) s)[i] == '\xBD');
    2035             :         }
    2036             :         /* if shrinking, write debug pattern into to-be-freed memory */
    2037     4179157 :         DEADBEEFCHK if (size < osize)
    2038     3119333 :                 memset((char *) s + size, '\xDB', osize - size);
    2039             :         os = s;
    2040     4179157 :         os[-1] |= 2;            /* indicate area is freed */
    2041             : #endif
    2042     4179157 :         s = realloc((char *) s - MALLOC_EXTRA_SPACE,
    2043             :                     nsize + MALLOC_EXTRA_SPACE + DEBUG_SPACE);
    2044     4179157 :         if (s == NULL) {
    2045             : #ifndef NDEBUG
    2046           0 :                 os[-1] &= ~2;       /* not freed after all */
    2047             : #endif
    2048           0 :                 GDKsyserror("realloc failed; memory requested: %zu, memory in use: %zu, virtual memory in use: %zu\n", size, GDKmem_cursize(), GDKvm_cursize());;
    2049             :                 return NULL;
    2050             :         }
    2051     4179157 :         s = (void *) ((char *) s + MALLOC_EXTRA_SPACE);
    2052             :         /* just before the pointer that we return, write how much we
    2053             :          * asked of malloc */
    2054     4179157 :         ((size_t *) s)[-1] = nsize + MALLOC_EXTRA_SPACE + DEBUG_SPACE;
    2055             : #ifndef NDEBUG
    2056             :         /* just before that, write how much was asked of us */
    2057     4179157 :         ((size_t *) s)[-2] = size;
    2058             :         /* if growing, initialize new memory with debug pattern */
    2059     4179157 :         DEADBEEFCHK if (size > osize)
    2060     1023293 :                 memset((char *) s + osize, '\xBD', size - osize);
    2061             :         /* write pattern to help find out-of-bounds writes */
    2062     4179157 :         memset((char *) s + size, '\xBD', nsize + DEBUG_SPACE - size);
    2063             : #endif
    2064             : 
    2065     4179157 :         heapinc(nsize + MALLOC_EXTRA_SPACE + DEBUG_SPACE);
    2066     4179157 :         heapdec((ssize_t) asize);
    2067             : 
    2068     4179157 :         return s;
    2069             : }
    2070             : 
    2071             : /* return how much memory was allocated; the argument must be a value
    2072             :  * returned by GDKmalloc, GDKzalloc, GDKrealloc, GDKstrdup, or
    2073             :  * GDKstrndup */
    2074             : size_t
    2075       75320 : GDKmallocated(const void *s)
    2076             : {
    2077       75320 :         return ((const size_t *) s)[-1]; /* how much allocated last */
    2078             : }
    2079             : 
    2080             : void
    2081        6507 : GDKsetmallocsuccesscount(lng count)
    2082             : {
    2083             :         (void) count;
    2084             : #ifndef NDEBUG
    2085        6507 :         GDK_malloc_success_count = count;
    2086             : #endif
    2087        6507 : }
    2088             : 
    2089             : /*
    2090             :  * @- virtual memory
    2091             :  * allocations affect only the logical VM resources.
    2092             :  */
    2093             : #undef GDKmmap
    2094             : void *
    2095        2049 : GDKmmap(const char *path, int mode, size_t len)
    2096             : {
    2097             :         void *ret;
    2098             : 
    2099        2049 :         if (GDKvm_cursize() + len >= GDK_vm_maxsize &&
    2100           0 :             !MT_thread_override_limits()) {
    2101           0 :                 GDKerror("requested too much virtual memory; memory requested: %zu, memory in use: %zu, virtual memory in use: %zu\n", len, GDKmem_cursize(), GDKvm_cursize());
    2102           0 :                 return NULL;
    2103             :         }
    2104        2051 :         ret = MT_mmap(path, mode, len);
    2105        2099 :         if (ret != NULL)
    2106        2099 :                 meminc(len);
    2107             :         else
    2108           0 :                 GDKerror("requesting virtual memory failed; memory requested: %zu, memory in use: %zu, virtual memory in use: %zu\n", len, GDKmem_cursize(), GDKvm_cursize());
    2109             :         return ret;
    2110             : }
    2111             : 
    2112             : #undef GDKmunmap
    2113             : gdk_return
    2114        2097 : GDKmunmap(void *addr, size_t size)
    2115             : {
    2116             :         int ret;
    2117             : 
    2118        2097 :         ret = MT_munmap(addr, size);
    2119        2099 :         if (ret == 0)
    2120        2099 :                 memdec(size);
    2121        2099 :         return ret == 0 ? GDK_SUCCEED : GDK_FAIL;
    2122             : }
    2123             : 
    2124             : #undef GDKmremap
    2125             : void *
    2126         510 : GDKmremap(const char *path, int mode, void *old_address, size_t old_size, size_t *new_size)
    2127             : {
    2128             :         void *ret;
    2129             : 
    2130         510 :         if (*new_size > old_size &&
    2131         510 :             GDKvm_cursize() + *new_size - old_size >= GDK_vm_maxsize &&
    2132           0 :             !MT_thread_override_limits()) {
    2133           0 :                 GDKerror("requested too much virtual memory; memory requested: %zu, memory in use: %zu, virtual memory in use: %zu\n", *new_size, GDKmem_cursize(), GDKvm_cursize());
    2134           0 :                 return NULL;
    2135             :         }
    2136         510 :         ret = MT_mremap(path, mode, old_address, old_size, new_size);
    2137         510 :         if (ret != NULL) {
    2138         510 :                 memdec(old_size);
    2139         510 :                 meminc(*new_size);
    2140             :         } else {
    2141           0 :                 GDKerror("requesting virtual memory failed; memory requested: %zu, memory in use: %zu, virtual memory in use: %zu\n", *new_size, GDKmem_cursize(), GDKvm_cursize());
    2142             :         }
    2143             :         return ret;
    2144             : }

Generated by: LCOV version 1.14