int ATOMunknown_find(const char *nme) { int i, j = 0; /* first try to find the atom */ MT_lock_set(&GDKthreadLock); for (i = 1; i < MAXATOMS; i++) { if (unknown[i]) { if (strcmp(unknown[i], nme) == 0) { MT_lock_unset(&GDKthreadLock); return -i; } } else if (j == 0) j = i; } if (j == 0) { /* no space for new atom (shouldn't happen) */ MT_lock_unset(&GDKthreadLock); return 0; } if ((unknown[j] = GDKstrdup(nme)) == NULL) { MT_lock_unset(&GDKthreadLock); return 0; } MT_lock_unset(&GDKthreadLock); return -j; }
sht PropertyIndex(str name) { int i=0; for (i=0; i<nr_properties; i++) { if (strcmp(properties[i], name) == 0) return i; } MT_lock_set(&mal_contextLock, "propertyIndex"); /* small change it's already added */ for (i=0; i<nr_properties; i++) { if (strcmp(properties[i], name) == 0) { MT_lock_unset(&mal_contextLock, "propertyIndex"); return i; } } if (i >= max_properties) { max_properties += 256; properties = GDKrealloc(properties, max_properties * sizeof(str)); if( properties == NULL){ GDKerror("PropertyIndex" MAL_MALLOC_FAIL); MT_lock_unset(&mal_contextLock, "propertyIndex"); return nr_properties; } } properties[nr_properties] = GDKstrdup(name); MT_lock_unset(&mal_contextLock, "propertyIndex"); return nr_properties++; }
static Client MCnewClient(void) { Client c; MT_lock_set(&mal_contextLock, "newClient"); if (mal_clients[CONSOLE].user && mal_clients[CONSOLE].mode == FINISHING) { /*system shutdown in progress */ MT_lock_unset(&mal_contextLock, "newClient"); return NULL; } for (c = mal_clients; c < mal_clients + MAL_MAXCLIENTS; c++) { if (c->mode == FREECLIENT) { c->mode = CLAIMED; break; } } MT_lock_unset(&mal_contextLock, "newClient"); if (c == mal_clients + MAL_MAXCLIENTS) return NULL; c->idx = (int) (c - mal_clients); #ifdef MAL_CLIENT_DEBUG printf("New client created %d\n", (int) (c - mal_clients)); #endif return c; }
str MRgetCloud(int *ret, str *mrcluster) { str msg; BAT *cloud; BUN p, q; BATiter bi; char nodes[BUFSIZ]; char *n = nodes; int mapcount = 0; snprintf(nodes, sizeof(nodes), "*/%s/node/*", *mrcluster); if ((msg = RMTresolve(ret, &n)) != MAL_SUCCEED) return msg; MT_lock_set(&mal_contextLock, "mapreduce"); cloud = BATdescriptor(*ret); /* should succeed */ mapnodes = (mapnode*)GDKzalloc(sizeof(mapnode) * (BATcount(cloud) + 1)); if (mapnodes == NULL) { BBPreleaseref(*ret); throw(MAL, "mapreduce.getCloud", MAL_MALLOC_FAIL); } bi = bat_iterator(cloud); BATloop(cloud, p, q) { str t = (str)BUNtail(bi, p); mapnodes[mapcount].uri = GDKstrdup(t); mapnodes[mapcount].user = GDKstrdup("monetdb"); mapnodes[mapcount].pass = GDKstrdup("monetdb"); mapcount++; }
node * list_remove_node(list *l, node *n) { void *data = n->data; node *p = l->h; if (p != n) while (p && p->next != n) p = p->next; if (p == n) { l->h = n->next; p = NULL; } else if ( p != NULL) { p->next = n->next; } if (n == l->t) l->t = p; node_destroy(l, n); l->cnt--; MT_lock_set(&l->ht_lock, "list_remove_node"); if (l->ht && data) hash_delete(l->ht, data); MT_lock_unset(&l->ht_lock, "list_remove_node"); return p; }
static void QOTstatisticsInit(void){ oid o=0; int i,j; if (qotStat[QOTnames]) return; #ifdef NEED_MT_LOCK_INIT MT_lock_init(&qotlock,"QOT statistics"); #endif MT_lock_set(&qotlock, "QOT statistics"); qotStat[QOTnames]= QOT_create("opt","names",TYPE_str); BATseqbase(qotStat[QOTnames],o); qotStat[QOTcalls]= QOT_create("opt","calls",TYPE_int); BATseqbase(qotStat[QOTcalls],o); qotStat[QOTactions]= QOT_create("opt","actions",TYPE_int); BATseqbase(qotStat[QOTactions],o); qotStat[QOTtimings]= QOT_create("opt","timings",TYPE_lng); BATseqbase(qotStat[QOTtimings],o); /* recover from errors */ for ( i=0; i<4; i++) if ( qotStat[i] == NULL){ for (j= 0; j < i; j++) BBPclear(qotStat[j]->batCacheid); MT_lock_unset(&qotlock, "QOT statistics"); return; } MT_lock_unset(&qotlock, "QOT statistics"); /* save them at least once */ QOTstatisticsExit(); }
/* * @+ Atomic Type Interface * The collection of built-in types supported for BATs can be extended * easily. In essence, the user should specify conversion routines * from values stored anywhere in memory to its equivalent in the BAT, * and vice verse. Some routines are required for coercion and to * support the BAT administration. * * A new type is incrementally build using the routine * ATOMallocate(id). The parameter id denotes the type name; an entry * is created if the type is so far unknown. * * The size describes the amount of space to be reserved in the BUN. * * The routine put takes a pointer to a memory resident copy and * prepares a persistent copy in the BAT passed. The inverse * operation is get. A new value can be directly included into the * BAT using new, which should prepare a null-value representation. A * value is removed from the BAT store using del, which can take care * of garbage collection and BAT administration. * * The pair tostr and fromstr should convert a reference to a * persistent value to a memory resident string equivalent. FromStr * takes a string and applies a put to store it within a BAT. They * are used to prepare for readable output/input and to support * coercion. * * The routines cmp and eq are comparison routines used to build * access structures. The null returns a reference to a null value * representation. * * The incremental atom construction uses hardwired properties. This * should be improved later on. */ int ATOMallocate(const char *id) { int t; if (strlen(id) >= IDLENGTH) { GDKerror("ATOMallocate: name too long"); return int_nil; } MT_lock_set(&GDKthreadLock); t = ATOMindex(id); if (t < 0) { t = -t; if (t == GDKatomcnt) { if (GDKatomcnt == MAXATOMS) { MT_lock_unset(&GDKthreadLock); GDKerror("ATOMallocate: too many types"); return int_nil; } GDKatomcnt++; } BATatoms[t] = (atomDesc) { .size = sizeof(int), /* default */ .linear = true, /* default */ .storage = t, /* default */ }; strcpy(BATatoms[t].name, id); } MT_lock_unset(&GDKthreadLock); return t; }
int THRprintf(stream *s, const char *format, ...) { str bf = THRprintbuf, p = 0; size_t bfsz = BUFSIZ; int n = 0; ptrdiff_t m = 0; char c; va_list ap; if (!s) return -1; MT_lock_set(&MT_system_lock, "THRprintf"); if (*format != '!') { c = '#'; if (*format == '#') format++; } else { c = '!'; format++; } do { p = bf; *p++ = c; if (GDKdebug & THRDMASK) { sprintf(p, "%02d ", THRgettid()); while (*p) p++; } m = p - bf; va_start(ap, format); n = vsnprintf(p, bfsz-m, format, ap); va_end(ap); if (n < 0) goto cleanup; if ((size_t) n < bfsz - m) break; /* normal loop exit, usually 1st iteration */ bfsz = m + n + 1; /* precisely what is needed */ if (bf != THRprintbuf) free(bf); bf = (str) malloc(bfsz); assert(bf != NULL); } while (1); p += n; n = 0; if (mnstr_write(s, bf, p - bf, 1) != 1) n = -1; cleanup: if (bf != THRprintbuf) free(bf); MT_lock_unset(&MT_system_lock, "THRprintf"); return n; }
/* * Create an interpreter pool. * One worker will adaptively be available for each client. * The remainder are taken from the GDKnr_threads argument and * typically is equal to the number of cores * The workers are assembled in a local table to enable debugging. */ static int DFLOWinitialize(void) { int i, limit; int created = 0; MT_lock_set(&mal_contextLock, "DFLOWinitialize"); if (todo) { /* somebody else beat us to it */ MT_lock_unset(&mal_contextLock, "DFLOWinitialize"); return 0; } todo = q_create(2048, "todo"); if (todo == NULL) { MT_lock_unset(&mal_contextLock, "DFLOWinitialize"); return -1; } for (i = 0; i < THREADS; i++) MT_sema_init(&workers[i].s, 0, "DFLOWinitialize"); limit = GDKnr_threads ? GDKnr_threads - 1 : 0; #ifdef NEED_MT_LOCK_INIT ATOMIC_INIT(exitingLock, "exitingLock"); MT_lock_init(&dataflowLock, "dataflowLock"); #endif MT_lock_set(&dataflowLock, "DFLOWinitialize"); for (i = 0; i < limit; i++) { workers[i].flag = RUNNING; workers[i].cntxt = NULL; if (MT_create_thread(&workers[i].id, DFLOWworker, (void *) &workers[i], MT_THR_JOINABLE) < 0) workers[i].flag = IDLE; else created++; } MT_lock_unset(&dataflowLock, "DFLOWinitialize"); if (created == 0) { /* no threads created */ q_destroy(todo); todo = NULL; MT_lock_unset(&mal_contextLock, "DFLOWinitialize"); return -1; } MT_lock_unset(&mal_contextLock, "DFLOWinitialize"); return 0; }
static void q_requeue(Queue *q, FlowEvent d) { assert(q); assert(d); MT_lock_set(&q->l, "q_requeue"); q_requeue_(q, d); MT_lock_unset(&q->l, "q_requeue"); MT_sema_up(&q->s, "q_requeue"); }
static FlowEvent q_dequeue(Queue *q, Client cntxt) { FlowEvent r = NULL; assert(q); MT_sema_down(&q->s, "q_dequeue"); if (ATOMIC_GET(exiting, exitingLock, "q_dequeue")) return NULL; MT_lock_set(&q->l, "q_dequeue"); if (cntxt) { int i; for (i = q->last - 1; i >= 0; i--) { if (q->data[i]->flow->cntxt == cntxt) { r = q->data[i]; q->last--; while (i < q->last) { q->data[i] = q->data[i + 1]; i++; } break; } } MT_lock_unset(&q->l, "q_dequeue"); return r; } if (q->exitcount > 0) { q->exitcount--; MT_lock_unset(&q->l, "q_dequeue"); return NULL; } assert(q->last > 0); if (q->last > 0) { /* LIFO favors garbage collection */ r = q->data[--q->last]; q->data[q->last] = 0; } /* else: terminating */ /* try out random draw * { int i; i = rand() % q->last; r = q->data[i]; for (i++; i < q->last; i++) q->data[i - 1] = q->data[i]; q->last--; i } */ MT_lock_unset(&q->l, "q_dequeue"); assert(r); return r; }
void stopMALdataflow(void) { int i; ATOMIC_SET(exiting, 1, exitingLock, "q_dequeue"); if (todo) { for (i = 0; i < THREADS; i++) MT_sema_up(&todo->s, "stopMALdataflow"); MT_lock_set(&dataflowLock, "stopMALdataflow"); for (i = 0; i < THREADS; i++) { if (workers[i].flag != IDLE && workers[i].flag != JOINING) { workers[i].flag = JOINING; MT_lock_unset(&dataflowLock, "stopMALdataflow"); MT_join_thread(workers[i].id); MT_lock_set(&dataflowLock, "stopMALdataflow"); } workers[i].flag = IDLE; } MT_lock_unset(&dataflowLock, "stopMALdataflow"); } }
static str SQLinit(void) { char *debug_str = GDKgetenv("sql_debug"), *msg = MAL_SUCCEED; int readonly = GDKgetenv_isyes("gdk_readonly"); int single_user = GDKgetenv_isyes("gdk_single_user"); const char *gmt = "GMT"; tzone tz; #ifdef _SQL_SCENARIO_DEBUG mnstr_printf(GDKout, "#SQLinit Monet 5\n"); #endif if (SQLinitialized) return MAL_SUCCEED; #ifdef NEED_MT_LOCK_INIT MT_lock_init(&sql_contextLock, "sql_contextLock"); #endif MT_lock_set(&sql_contextLock); memset((char *) &be_funcs, 0, sizeof(backend_functions)); be_funcs.fstack = &monet5_freestack; be_funcs.fcode = &monet5_freecode; be_funcs.fresolve_function = &monet5_resolve_function; monet5_user_init(&be_funcs); msg = MTIMEtimezone(&tz, &gmt); if (msg) return msg; (void) tz; if (debug_str) SQLdebug = strtol(debug_str, NULL, 10); if (single_user) SQLdebug |= 64; if (readonly) SQLdebug |= 32; if ((SQLnewcatalog = mvc_init(SQLdebug, store_bat, readonly, single_user, 0)) < 0) throw(SQL, "SQLinit", "Catalogue initialization failed"); SQLinitialized = TRUE; MT_lock_unset(&sql_contextLock); if (MT_create_thread(&sqllogthread, (void (*)(void *)) mvc_logmanager, NULL, MT_THR_DETACHED) != 0) { throw(SQL, "SQLinit", "Starting log manager failed"); } #if 0 if (MT_create_thread(&minmaxthread, (void (*)(void *)) mvc_minmaxmanager, NULL, MT_THR_DETACHED) != 0) { throw(SQL, "SQLinit", "Starting minmax manager failed"); } #endif return MAL_SUCCEED; }
/* * Currently each user can define a new scenario, provided we have a free slot. * Scenarios not hardwired can always be dropped. */ Scenario getFreeScenario(void) { int i; Scenario scen = NULL; MT_lock_set(&scenarioLock); for (i = 0; i < MAXSCEN && scenarioRec[i].name; i++) ; if (i < MAXSCEN) scen = scenarioRec + i; MT_lock_unset(&scenarioLock); return scen; }
void THRdel(Thread t) { if (t < GDKthreads || t > GDKthreads + THREADS) { GDKfatal("THRdel: illegal call\n"); } MT_lock_set(&GDKthreadLock, "THRdel"); /* The stream may haven been closed (e.g. in freeClient) causing an abort PARDEBUG THRprintf(GDKstdout, "#pid = " SZFMT ", disconnected, %d left\n", (size_t) t->pid, GDKnrofthreads); */ t->pid = 0; GDKnrofthreads--; MT_lock_unset(&GDKthreadLock, "THRdel"); }
void ATOMunknown_clean(void) { int i; MT_lock_set(&GDKthreadLock); for (i = 1; i < MAXATOMS; i++) { if(unknown[i]) { GDKfree(unknown[i]); unknown[i] = NULL; } else { break; } } MT_lock_unset(&GDKthreadLock); }
void MCstopClients(Client cntxt) { Client c = mal_clients; MT_lock_set(&mal_contextLock); for(c= mal_clients +1; c < mal_clients+MAL_MAXCLIENTS; c++) if( cntxt != c){ if ( c->mode == RUNCLIENT) c->mode = FINISHCLIENT; else if (c->mode == FREECLIENT) c->mode = BLOCKCLIENT; } shutdowninprogress =1; MT_lock_unset(&mal_contextLock); }
/* * A scenario is initialized only once per session. * All other requests are silently ignored. * After initialization, all state functions should have been set. * Initialization includes searching for the scenario startup file in * the etc/MonetDB directory. This creates a dependency, because the * malInclude also needs a scenario. To break this cycle, the system should * call once the routine default scenario for each client first. */ static str initScenario(Client c, Scenario s) { str l = s->language; str msg = MAL_SUCCEED; if (s->initSystemCmd) return(fillScenario(c, s)); /* prepare for conclicts */ MT_lock_set(&mal_contextLock); if (s->initSystem && s->initSystemCmd == 0) { s->initSystemCmd = (MALfcn) getAddress(s->initSystem); if (s->initSystemCmd) { msg = (*s->initSystemCmd) (c); } else { char buf[BUFSIZ]; snprintf(buf,BUFSIZ,"%s.init", l); msg = createException(MAL, buf, "Scenario not initialized"); } } if (msg) { MT_lock_unset(&mal_contextLock); return msg; } if (s->exitSystem && s->exitSystemCmd == 0) s->exitSystemCmd = (MALfcn) getAddress(s->exitSystem); if (s->initClient && s->initClientCmd == 0) s->initClientCmd = (MALfcn) getAddress(s->initClient); if (s->exitClient && s->exitClientCmd == 0) s->exitClientCmd = (MALfcn) getAddress(s->exitClient); if (s->reader && s->readerCmd == 0) s->readerCmd = (MALfcn) getAddress(s->reader); if (s->parser && s->parserCmd == 0) s->parserCmd = (MALfcn) getAddress(s->parser); if (s->optimizer && s->optimizerCmd == 0) s->optimizerCmd = (MALfcn) getAddress(s->optimizer); if (s->tactics && s->tacticsCmd == 0) s->tacticsCmd = (MALfcn) getAddress(s->tactics); if (s->callback && s->callbackCmd == 0) s->callbackCmd = (MALfcn) getAddress(s->callback); if (s->engine && s->engineCmd == 0) s->engineCmd = (MALfcn) getAddress(s->engine); MT_lock_unset(&mal_contextLock); return(fillScenario(c, s)); }
int MCvalid(Client tc) { Client c; if (tc == NULL) { return 0; } MT_lock_set(&mal_contextLock); for (c = mal_clients; c < mal_clients + MAL_MAXCLIENTS; c++) { if (c == tc && c->mode == RUNCLIENT) { MT_lock_unset(&mal_contextLock); return 1; } } MT_lock_unset(&mal_contextLock); return 0; }
static void MRcleanCloud(void) { int i; MT_lock_set(&mal_contextLock, "mapreduce"); for (i = 0; mapnodes[i].uri; i++) { if (mapnodes[i].uri != NULL) GDKfree(mapnodes[i].uri); if (mapnodes[i].user != NULL) GDKfree(mapnodes[i].user); if (mapnodes[i].pass != NULL) GDKfree(mapnodes[i].pass); mapnodes[i].uri = mapnodes[i].user = mapnodes[i].pass = 0; } MT_lock_unset(&mal_contextLock, "mapreduce"); }
void QOTstatisticsExit(void) { bat names[5]; if( qotStat[QOTnames] == NULL) return; MT_lock_set(&qotlock, "QOT statistics"); names[0] = 0; names[1] = abs(qotStat[QOTnames]->batCacheid); names[2] = abs(qotStat[QOTcalls]->batCacheid); names[3] = abs(qotStat[QOTactions]->batCacheid); names[4] = abs(qotStat[QOTtimings]->batCacheid); TMsubcommit_list(names, 5); MT_lock_unset(&qotlock, "QOT statistics"); }
Thread THRnew(str name) { int tid = 0; Thread t; Thread s; MT_Id pid = MT_getpid(); MT_lock_set(&GDKthreadLock, "THRnew"); s = GDK_find_thread(pid); if (s == NULL) { for (s = GDKthreads, t = s + THREADS; s < t; s++) { if (s->pid == pid) { MT_lock_unset(&GDKthreadLock, "THRnew"); IODEBUG THRprintf(GDKstdout, "#THRnew:duplicate " SZFMT "\n", (size_t) pid); return s; } } for (s = GDKthreads, t = s + THREADS; s < t; s++) { if (s->pid == 0) { break; } } if (s == t) { MT_lock_unset(&GDKthreadLock, "THRnew"); IODEBUG THRprintf(GDKstdout, "#THRnew: too many threads\n"); return NULL; } tid = s->tid; memset((char *) s, 0, sizeof(*s)); s->pid = pid; s->tid = tid; s->data[1] = THRdata[1]; s->data[0] = THRdata[0]; s->sp = THRsp(); PARDEBUG THRprintf(GDKstdout, "#%x " SZFMT " sp = " SZFMT "\n", s->tid, (size_t) pid, s->sp); PARDEBUG THRprintf(GDKstdout, "#nrofthreads %d\n", GDKnrofthreads); GDKnrofthreads++; } s->name = name; MT_lock_unset(&GDKthreadLock, "THRnew"); return s; }
static void run_process_bam_alignments(void *d) { reader_thread_data *data = (reader_thread_data *) d; bam_wrapper *bw; TO_LOG("<Thread %d> Starting on next file...\n", data->thread_id); /* First, find out on which bam wrapper we have to work */ MT_lock_set(data->reader_lock); if (*data->cur_file == data->nr_files - 1) { /* The last file is already (being) processed, this * thread is done */ MT_lock_unset(data->reader_lock); TO_LOG("<Thread %d> No files left to work on; thread done\n", data->thread_id); return; } (*data->cur_file) += 1; bw = &data->bws[*data->cur_file]; MT_lock_unset(data->reader_lock); TO_LOG("<Thread %d> Processing alignments of file '%s' (file id " LLFMT ")...\n", data->thread_id, bw->file_location, bw->file_id); if ((data->msg = process_alignments(bw, data->failure)) != MAL_SUCCEED) { TO_LOG("<Thread %d> Error while processing alignments of file '%s' (file id " LLFMT ") (%s)\n", data->thread_id, bw->file_location, bw->file_id, data->msg); REUSE_EXCEPTION(data->msg, MAL, "run_process_bam_alignments", "Error while processing alignments of file '%s' (file id " LLFMT "): %s", bw->file_location, bw->file_id, data->msg); return; } if (*data->failure) { /* process_bam_alignments returned because another * thread failed and not because this thread failed */ TO_LOG("<Thread %d> Exit due to failure in other thread\n", data->thread_id); return; } TO_LOG("<Thread %d> All alignments in file '%s' (file id " LLFMT ") processed!\n", data->thread_id, bw->file_location, bw->file_id); run_process_bam_alignments(d); }
void list_move_data(list *s, list *d, void *data) { node *n; for (n = s->h; n; n = n->next) { if (n->data == data) { MT_lock_set(&s->ht_lock, "list_move_data"); if (s->ht && n->data) hash_delete(s->ht, n->data); MT_lock_unset(&s->ht_lock, "list_move_data"); n->data = NULL; /* make sure data isn't destroyed */ list_remove_node(s, n); break; } } list_append(d, data); }
void list_remove_data(list *s, void *data) { node *n; /* maybe use compare func */ for (n = s->h; n; n = n->next) { if (n->data == data) { MT_lock_set(&s->ht_lock, "list_remove_data"); if (s->ht && n->data) hash_delete(s->ht, n->data); MT_lock_unset(&s->ht_lock, "list_remove_data"); n->data = NULL; list_remove_node(s, n); break; } } }
/* * For analysis of memory leaks we should cleanup the libraries before * we exit the server. This does not involve the libraries themselves, * because they may still be in use. */ void mal_linker_reset(void) { int i; MT_lock_set(&mal_contextLock); for (i = 0; i < lastfile; i++){ if (filesLoaded[i].fullname) { /* dlclose(filesLoaded[i].handle);*/ GDKfree(filesLoaded[i].modname); GDKfree(filesLoaded[i].fullname); } filesLoaded[i].modname = NULL; filesLoaded[i].fullname = NULL; } lastfile = 0; MT_lock_unset(&mal_contextLock); }
/* * @- * Currently each user can define a new scenario, provided we have a free slot. * Scenarios not hardwired can always be dropped. */ Scenario getFreeScenario(void) { int i; Scenario scen = NULL; MT_lock_set(&scenarioLock, "getFreeScenario"); for (i = 0; i < MAXSCEN && scenarioRec[i].name; i++) ; if (i == MAXSCEN) { showException(GDKout, MAL,"freeScenario", "no scenario space left (%d); adjust MAXSCEN and recompile", MAXSCEN); } else { scen = scenarioRec + i; } MT_lock_unset(&scenarioLock, "getFreeScenario"); return scen; }
list * list_prepend(list *l, void *data) { node *n = node_create(l->sa, data); if (!l->cnt) { l->t = n; } n->next = l->h; l->h = n; l->cnt++; MT_lock_set(&l->ht_lock, "list_prepend"); if (l->ht) { int key = l->ht->key(data); hash_add(l->ht, key, data); } MT_lock_unset(&l->ht_lock, "list_prepend"); return l; }
str MALreader(Client c) { int r = 1; if (c == mal_clients) { r = readConsole(c); if (r < 0 && c->fdin->eof == 0) r = MCreadClient(c); if (r > 0) return MAL_SUCCEED; } else if (MCreadClient(c) > 0) return MAL_SUCCEED; MT_lock_set(&mal_contextLock); c->mode = FINISHCLIENT; MT_lock_unset(&mal_contextLock); if (c->fdin) c->fdin->buf[c->fdin->pos] = 0; else throw(MAL, "mal.reader", RUNTIME_IO_EOF); return MAL_SUCCEED; }
str RAPIprelude(void *ret) { (void) ret; if (RAPIEnabled()) { MT_lock_set(&rapiLock); /* startup internal R environment */ if (!rapiInitialized) { char *initstatus; initstatus = RAPIinitialize(); if (initstatus != 0) { MT_lock_unset(&rapiLock); throw(MAL, "rapi.eval", "failed to initialize R environment (%s)", initstatus); } Rf_defineVar(Rf_install("MONETDB_LIBDIR"), ScalarString(RSTR(LIBDIR)), R_GlobalEnv); } MT_lock_unset(&rapiLock); printf("# MonetDB/R module loaded\n"); } return MAL_SUCCEED; }