Changeset: f4be0fd3e9c1 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=f4be0fd3e9c1
Modified Files:
clients/Tests/exports.stable.out
gdk/gdk.h
gdk/gdk_utils.c
gdk/gdk_utils.h
monetdb5/mal/mal.c
monetdb5/modules/mal/mal_mapi.c
sql/backends/monet5/sql_scenario.c
sql/server/sql_mvc.c
Branch: default
Log Message:
We must *never* call MT_kill_thread. Instead we register to-be-waited for
threads.
MT_kill_thread() must not be called, because we cannot be sure the
killed thread doesn't hold any locks. If it does it is almost a
guarantee for deadlock.
Introducing GDKregister() to register a thread ID that is to be waited
for when the server exits. The thread *must* exit when GDKexiting()
returns true. Also, the thread *must* be started using
MT_THR_JOINABLE. MT_THR_DETACHED may now only be used by short
running threads that can not be easily waited for (currently only the
thread that persists the hash or imprints heap).
Also introducing GDKprepareExit() that is to be called early on when
exiting. This call will cause subsequent calls to GDKexiting() to
return true (so that threads know they must exit).
diffs (272 lines):
diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out
--- a/clients/Tests/exports.stable.out
+++ b/clients/Tests/exports.stable.out
@@ -233,9 +233,11 @@ size_t GDKmem_cursize(void);
void *GDKmmap(const char *path, int mode, size_t len);
int GDKms(void);
int GDKnr_threads;
+void GDKprepareExit(void);
void GDKqsort(void *h, void *t, const void *base, size_t n, int hs, int ts,
int tpe);
void GDKqsort_rev(void *h, void *t, const void *base, size_t n, int hs, int
ts, int tpe);
void *GDKrealloc(void *pold, size_t size)
__attribute__((__warn_unused_result__));
+void GDKregister(MT_Id pid);
void GDKreset(int status);
void GDKsetenv(str name, str value);
ssize_t GDKstrFromStr(unsigned char *dst, const unsigned char *src, ssize_t
len);
diff --git a/gdk/gdk.h b/gdk/gdk.h
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -2455,7 +2455,6 @@ VALptr(const ValRecord *v)
typedef struct threadStruct {
int tid; /* logical ID by MonetDB; val == index into
this array + 1 (0 is invalid) */
- int waitfor; /* waitfor on exit */
MT_Id pid; /* physical thread id (pointer-sized) from the
OS thread library */
str name;
ptr data[THREADDATA];
diff --git a/gdk/gdk_utils.c b/gdk/gdk_utils.c
--- a/gdk/gdk_utils.c
+++ b/gdk/gdk_utils.c
@@ -1238,15 +1238,44 @@ GDKexiting(void)
return stopped;
}
+void
+GDKprepareExit(void)
+{
+ if (ATOMIC_TAS(GDKstopped, GDKstoppedLock) != 0)
+ return;
+ if (GDKvmtrim_id)
+ MT_join_thread(GDKvmtrim_id);
+}
+
+static struct serverthread {
+ struct serverthread *next;
+ MT_Id pid;
+} *serverthread;
+
+/* Register a thread that should be waited for in GDKreset. The
+ * thread must exit by itself when GDKexiting() returns true. */
+void
+GDKregister(MT_Id pid)
+{
+ struct serverthread *st;
+
+ if ((st = GDKmalloc(sizeof(struct serverthread))) == NULL)
+ return;
+ st->pid = pid;
+ MT_lock_set(&GDKthreadLock);
+ st->next = serverthread;
+ serverthread = st;
+ MT_lock_unset(&GDKthreadLock);
+}
+
/* coverity[+kill] */
void
GDKreset(int status)
{
MT_Id pid = MT_getpid();
Thread t, s;
+ struct serverthread *st;
- if (ATOMIC_TAS(GDKstopped, GDKstoppedLock) != 0)
- return ;
if( GDKkey){
BBPunfix(GDKkey->batCacheid);
GDKkey = 0;
@@ -1255,16 +1284,15 @@ GDKreset(int status)
BBPunfix(GDKval->batCacheid);
GDKval = 0;
}
- if (GDKvmtrim_id)
- MT_join_thread(GDKvmtrim_id);
MT_lock_set(&GDKthreadLock);
- for (t = GDKthreads, s = t + THREADS; t < s; t++)
- if (t->pid && t->pid != pid && t->waitfor) {
- MT_lock_unset(&GDKthreadLock);
- MT_join_thread(t->pid);
- MT_lock_set(&GDKthreadLock);
- }
+ for (st = serverthread; st; st = serverthread) {
+ MT_lock_unset(&GDKthreadLock);
+ MT_join_thread(st->pid);
+ MT_lock_set(&GDKthreadLock);
+ serverthread = st->next;
+ GDKfree(st);
+ }
MT_lock_unset(&GDKthreadLock);
if (status == 0) {
@@ -1333,6 +1361,7 @@ GDKexit(int status)
/* no database lock, so no threads, so exit now */
exit(status);
}
+ GDKprepareExit();
GDKreset(status);
MT_exit_thread(-1);
}
diff --git a/gdk/gdk_utils.h b/gdk/gdk_utils.h
--- a/gdk/gdk_utils.h
+++ b/gdk/gdk_utils.h
@@ -90,6 +90,8 @@ gdk_export int GDKnr_threads;
__attribute__((__noreturn__));
gdk_export int GDKexiting(void);
+gdk_export void GDKregister(MT_Id pid);
+gdk_export void GDKprepareExit(void);
gdk_export void GDKreset(int status);
gdk_export const char *GDKversion(void);
diff --git a/monetdb5/mal/mal.c b/monetdb5/mal/mal.c
--- a/monetdb5/mal/mal.c
+++ b/monetdb5/mal/mal.c
@@ -106,6 +106,7 @@ int mal_init(void){
initProfiler();
return 0;
}
+
/*
* Upon exit we should attempt to remove all allocated memory explicitly.
* This seemingly superflous action is necessary to simplify analyis of
@@ -116,13 +117,15 @@ int mal_init(void){
* activity first.
* This function should be called after you have issued sql_reset();
*/
-void mserver_reset(void){
+void mserver_reset(void)
+{
str err = 0;
- MCstopClients(0);
- setHeartbeat(-1);
- stopProfiler();
- RECYCLEdrop(mal_clients);
+ GDKprepareExit();
+ MCstopClients(0);
+ setHeartbeat(-1);
+ stopProfiler();
+ RECYCLEdrop(mal_clients);
AUTHreset();
if ((err = msab_wildRetreat()) != NULL) {
fprintf(stderr, "!%s", err);
@@ -141,18 +144,17 @@ void mserver_reset(void){
mal_client_reset();
mal_module_reset();
mal_module_reset();
- mal_linker_reset();
+ mal_linker_reset();
mal_resource_reset();
mal_runtime_reset();
mal_scenario_reset();
-
+
memset((char*)monet_cwd,0, sizeof(monet_cwd));
monet_memory = 0;
memset((char*)monet_characteristics,0, sizeof(monet_characteristics));
- mal_trace = 0;
-/* No need to clean up the namespace, it will simply be extended upon restart
- mal_namespace_reset();
-*/
+ mal_trace = 0;
+ /* No need to clean up the namespace, it will simply be extended
+ * upon restart mal_namespace_reset(); */
}
diff --git a/monetdb5/modules/mal/mal_mapi.c b/monetdb5/modules/mal/mal_mapi.c
--- a/monetdb5/modules/mal/mal_mapi.c
+++ b/monetdb5/modules/mal/mal_mapi.c
@@ -359,7 +359,7 @@ SERVERlistenThread(SOCKET *Sock)
data = GDKmalloc(sizeof(*data));
data->in = socket_rastream(msgsock, "Server read");
data->out = socket_wastream(msgsock, "Server write");
- if (MT_create_thread(&tid, doChallenge, data, MT_THR_DETACHED))
{
+ if (MT_create_thread(&tid, doChallenge, data, MT_THR_JOINABLE))
{
mnstr_printf(data->out, "!internal server error (cannot
fork new "
"client thread), please try
again later\n");
mnstr_flush(data->out);
@@ -367,6 +367,7 @@ SERVERlistenThread(SOCKET *Sock)
"cannot fork new client
thread");
GDKfree(data);
}
+ GDKregister(tid);
} while (!ATOMIC_GET(serverexiting, atomicLock) &&
!GDKexiting());
(void) ATOMIC_DEC(nlistener, atomicLock);
@@ -433,7 +434,7 @@ SERVERlisten(int *Port, str *Usockfile,
SOCKLEN length = 0;
int on = 1;
int i = 0;
- MT_Id pid, *pidp = &pid;
+ MT_Id pid;
int port;
int maxusers;
char *usockfile;
@@ -635,12 +636,13 @@ SERVERlisten(int *Port, str *Usockfile,
psock[1] = INVALID_SOCKET;
#endif
psock[2] = INVALID_SOCKET;
- if (MT_create_thread(pidp, (void (*)(void *)) SERVERlistenThread,
psock, MT_THR_DETACHED) != 0) {
+ if (MT_create_thread(&pid, (void (*)(void *)) SERVERlistenThread,
psock, MT_THR_JOINABLE) != 0) {
GDKfree(psock);
if (usockfile)
GDKfree(usockfile);
throw(MAL, "mal_mapi.listen", OPERATION_FAILED ": starting
thread failed");
}
+ GDKregister(pid);
#ifdef DEBUG_SERVER
gethostname(host, (int) 512);
snprintf(msg, (int) 512, "#Ready to accept connections on %s:%d\n",
host, port);
@@ -746,7 +748,7 @@ SERVERclient(void *res, const Stream *In
data = GDKmalloc(sizeof(*data));
data->in = *In;
data->out = *Out;
- if (MT_create_thread(&tid, doChallenge, data, MT_THR_DETACHED)) {
+ if (MT_create_thread(&tid, doChallenge, data, MT_THR_JOINABLE)) {
mnstr_printf(data->out, "!internal server error (cannot fork
new "
"client thread), please try again
later\n");
mnstr_flush(data->out);
@@ -754,6 +756,7 @@ SERVERclient(void *res, const Stream *In
"cannot fork new client thread");
free(data);
}
+ GDKregister(tid);
return MAL_SUCCEED;
}
diff --git a/sql/backends/monet5/sql_scenario.c
b/sql/backends/monet5/sql_scenario.c
--- a/sql/backends/monet5/sql_scenario.c
+++ b/sql/backends/monet5/sql_scenario.c
@@ -255,10 +255,12 @@ SQLinit(void)
if (MT_create_thread(&sqllogthread, (void (*)(void *)) mvc_logmanager,
NULL, MT_THR_JOINABLE) != 0) {
throw(SQL, "SQLinit", "Starting log manager failed");
}
+ GDKregister(sqllogthread);
#if 0
if (MT_create_thread(&minmaxthread, (void (*)(void *))
mvc_minmaxmanager, NULL, MT_THR_JOINABLE) != 0) {
throw(SQL, "SQLinit", "Starting minmax manager failed");
}
+ GDKregister(minmaxthread);
#endif
return MAL_SUCCEED;
}
diff --git a/sql/server/sql_mvc.c b/sql/server/sql_mvc.c
--- a/sql/server/sql_mvc.c
+++ b/sql/server/sql_mvc.c
@@ -155,7 +155,6 @@ mvc_logmanager(void)
{
Thread thr = THRnew("logmanager");
- thr->waitfor = 1;
store_manager();
THRdel(thr);
}
@@ -165,7 +164,6 @@ mvc_minmaxmanager(void)
{
Thread thr = THRnew("minmaxmanager");
- thr->waitfor = 1;
minmax_manager();
THRdel(thr);
}
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list