LCOV - code coverage report
Current view: top level - gdk - gdk_utils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 749 1054 71.1 %
Date: 2024-04-26 00:35:57 Functions: 54 57 94.7 %

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

Generated by: LCOV version 1.14