Changeset: 94cb82d10868 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=94cb82d10868
Modified Files:
clients/Tests/exports.stable.out
gdk/gdk_system.c
gdk/gdk_system.h
Branch: default
Log Message:
Implemented semaphores using atomic instructions on capable systems.
diffs (truncated from 350 to 300 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
@@ -276,6 +276,10 @@ int GDKnr_threads;
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);
+ATOMIC_TYPE volatile GDKsemacnt;
+MT_Sema *volatile GDKsemalist;
+ATOMIC_TYPE volatile GDKsemasleepcnt;
+ATOMIC_TYPE volatile GDKsemawaitcnt;
void GDKsetenv(str name, str value);
ssize_t GDKstrFromStr(unsigned char *dst, const unsigned char *src, ssize_t
len);
str GDKstrdup(const char *s);
diff --git a/gdk/gdk_system.c b/gdk/gdk_system.c
--- a/gdk/gdk_system.c
+++ b/gdk/gdk_system.c
@@ -71,9 +71,14 @@ MT_Lock MT_system_lock MT_LOCK_INITIALIZ
ATOMIC_TYPE volatile GDKlockcnt;
ATOMIC_TYPE volatile GDKlockcontentioncnt;
ATOMIC_TYPE volatile GDKlocksleepcnt;
+ATOMIC_TYPE volatile GDKsemacnt;
+ATOMIC_TYPE volatile GDKsemawaitcnt;
+ATOMIC_TYPE volatile GDKsemasleepcnt;
MT_Lock * volatile GDKlocklist;
+MT_Sema * volatile GDKsemalist;
-/* merge sort of linked list */
+/* merge sort of linked list
+ * these two functions are nearly identical */
static MT_Lock *
sortlocklist(MT_Lock *l)
{
@@ -131,12 +136,59 @@ sortlocklist(MT_Lock *l)
return t;
}
+static MT_Sema *
+sortsemalist(MT_Sema *l)
+{
+ MT_Sema *r, *t, *ll = NULL;
+
+ if (l == NULL || l->next == NULL)
+ return l;
+ for (t = r = l; t && t->next; t = t->next->next) {
+ ll = r;
+ r = r->next;
+ }
+ ll->next = NULL;
+ l = sortsemalist(l);
+ r = sortsemalist(r);
+ t = ll = NULL;
+ while (l && r) {
+ if (l->waitcount < r->waitcount ||
+ (l->waitcount == r->waitcount &&
+ l->sleep < r->sleep) ||
+ (l->waitcount == r->waitcount &&
+ l->sleep == r->sleep &&
+ l->count <= r->count)) {
+ if (ll == NULL) {
+ assert(t == NULL);
+ t = ll = l;
+ } else {
+ ll->next = l;
+ ll = ll->next;
+ }
+ l = l->next;
+ } else {
+ if (ll == NULL) {
+ assert(t == NULL);
+ t = ll = r;
+ } else {
+ ll->next = r;
+ ll = ll->next;
+ }
+ r = r->next;
+ }
+ }
+ ll->next = l ? l : r;
+ return t;
+}
+
void
GDKlockstatistics(int what)
{
MT_Lock *l;
+ MT_Sema *s;
GDKlocklist = sortlocklist(GDKlocklist);
+ GDKsemalist = sortsemalist(GDKsemalist);
for (l = GDKlocklist; l; l = l->next)
if (what == 0 ||
(what == 1 && l->count) ||
@@ -146,9 +198,16 @@ GDKlockstatistics(int what)
l->name ? l->name : "unknown",
l->count, l->contention, l->sleep,
what != 3 && l->lock ? "\tlocked" : "");
+ for (s = GDKsemalist; s; s = s->next)
+ fprintf(stderr, "#sema %-18s\t" SZFMT "\t" SZFMT "\t" SZFMT
"\n",
+ s->name ? s->name : "unknown",
+ s->count, s->waitcount, s->sleep);
fprintf(stderr, "#total lock count " SZFMT "\n", (size_t) GDKlockcnt);
fprintf(stderr, "#lock contention " SZFMT "\n", (size_t)
GDKlockcontentioncnt);
fprintf(stderr, "#lock sleep count " SZFMT "\n", (size_t)
GDKlocksleepcnt);
+ fprintf(stderr, "#total sema count " SZFMT "\n", (size_t) GDKsemacnt);
+ fprintf(stderr, "#sema wait count " SZFMT "\n", (size_t)
GDKsemawaitcnt);
+ fprintf(stderr, "#sema sleep count " SZFMT "\n", (size_t)
GDKsemasleepcnt);
}
#endif
diff --git a/gdk/gdk_system.h b/gdk/gdk_system.h
--- a/gdk/gdk_system.h
+++ b/gdk/gdk_system.h
@@ -192,6 +192,51 @@ typedef pthread_mutex_t MT_Lock;
#define NEED_MT_LOCK_INIT
#endif
+/*
+ * @- MT Semaphore API
+ */
+#if !defined(HAVE_PTHREAD_H) && defined(_MSC_VER)
+
+typedef HANDLE pthread_sema_t;
+gdk_export void pthread_sema_init(pthread_sema_t *s, int flag, int nresources);
+gdk_export void pthread_sema_destroy(pthread_sema_t *s);
+gdk_export void pthread_sema_up(pthread_sema_t *s);
+gdk_export void pthread_sema_down(pthread_sema_t *s);
+
+#elif defined(_AIX) || defined(__MACH__)
+
+typedef struct {
+ int cnt;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+} pthread_sema_t;
+
+gdk_export void pthread_sema_init(pthread_sema_t *s, int flag, int nresources);
+gdk_export void pthread_sema_destroy(pthread_sema_t *s);
+gdk_export void pthread_sema_up(pthread_sema_t *s);
+gdk_export void pthread_sema_down(pthread_sema_t *s);
+
+#else
+
+#define pthread_sema_t sem_t
+#define pthread_sema_init sem_init
+#define pthread_sema_destroy sem_destroy
+#define pthread_sema_up sem_post
+#define pthread_sema_down(x) while(sem_wait(x))
+
+#endif
+
+typedef pthread_sema_t MT_Sema;
+
+#define MT_sema_init(s, nr, n) \
+ do { \
+ pthread_sema_init((s), 0, nr); \
+ MT_locktrace_set((s), n); \
+ } while (0)
+#define MT_sema_destroy(s) pthread_sema_destroy(s)
+#define MT_sema_up(s, n) MT_log(pthread_sema_up(s), (s), "MT_up_sema",
n, stderr)
+#define MT_sema_down(s, n) MT_log_trace(pthread_sema_down(s), (s),
"MT_down_sema", n, stderr, s)
+
#else
/* if NDEBUG is not set, i.e., if assertions are enabled, we maintain
@@ -207,15 +252,31 @@ typedef struct MT_Lock {
#endif
} MT_Lock;
+typedef struct MT_Sema {
+ int volatile lock;
+ int volatile sema;
+#ifndef NDEBUG
+ size_t count;
+ size_t waitcount;
+ size_t sleep;
+ struct MT_Sema * volatile next;
+ const char *name;
+#endif
+} MT_Sema;
+
#ifndef NDEBUG
#define MT_LOCK_INITIALIZER(name) = {0, 0, 0, 0, (struct MT_Lock *) -1,
name}
gdk_export void GDKlockstatistics(int);
gdk_export MT_Lock * volatile GDKlocklist;
+gdk_export MT_Sema * volatile GDKsemalist;
gdk_export ATOMIC_TYPE volatile GDKlockcnt;
gdk_export ATOMIC_TYPE volatile GDKlockcontentioncnt;
gdk_export ATOMIC_TYPE volatile GDKlocksleepcnt;
+gdk_export ATOMIC_TYPE volatile GDKsemacnt;
+gdk_export ATOMIC_TYPE volatile GDKsemawaitcnt;
+gdk_export ATOMIC_TYPE volatile GDKsemasleepcnt;
#ifdef _MSC_VER
#if SIZEOF_SIZE_T == 8
#define ATOMIC_XCG_ptr(var, val) _InterlockedExchange64(&var, val)
@@ -274,6 +335,48 @@ gdk_export ATOMIC_TYPE volatile GDKlocks
} \
} while (!_done); \
} while (0)
+#define _DBG_SEMA_INIT(s, n) \
+ do { \
+ (s)->name = n; \
+ (s)->count = 0; \
+ (s)->waitcount = 0; \
+ (s)->sleep = 0; \
+ (s)->next = ATOMIC_XCG_ptr(GDKsemalist, (s)); \
+ } while (0)
+#define _DBG_SEMA_DESTROY(s) \
+ do { \
+ MT_Sema * volatile _p; \
+ int _done = 0; \
+ /* save a copy for statistical purposes */ \
+ _p = GDKmalloc(sizeof(MT_Sema)); \
+ memcpy(_p, s, sizeof(MT_Sema)); \
+ _p->next = ATOMIC_XCG_ptr(GDKsemalist, _p); \
+ do { \
+ if (ATOMIC_CAS_ptr(GDKsemalist, (s), (s)->next) == (s))
\
+ break; \
+ for (_p = GDKsemalist; _p; _p = _p->next) \
+ if (ATOMIC_CAS_ptr(_p->next, (s), (s)->next) ==
(s)) { \
+ _done = 1; \
+ break; \
+ } \
+ } while (!_done); \
+ } while (0)
+#define _DBG_SEMA_COUNT_0(s, n) ATOMIC_INC(GDKsemacnt, dummy, n)
+#define _DBG_SEMA_COUNT_1(s) ((s)->count++)
+#define _DBG_SEMA_WAIT(s, n) \
+ do { \
+ (s)->waitcount++; \
+ ATOMIC_INC(GDKsemawaitcnt, dummy, n); \
+ } while (0)
+#define _DBG_SEMA_SLEEP(s, n) \
+ do { \
+ if (_spincnt == 1024) \
+ ATOMIC_INC(GDKsemasleepcnt, dummy, n); \
+ } while (0)
+#define _DBG_SEMA_COUNT_2(s) \
+ do { \
+ (s)->sleep += _spincnt >= 1024; \
+ } while (0)
#else
@@ -286,6 +389,13 @@ gdk_export ATOMIC_TYPE volatile GDKlocks
#define _DBG_LOCK_COUNT_2(l) ((void) 0)
#define _DBG_LOCK_INIT(l, n) ((void) n)
#define _DBG_LOCK_DESTROY(l) ((void) 0)
+#define _DBG_SEMA_INIT(s, n) ((void) n)
+#define _DBG_SEMA_DESTROY(s) ((void) 0)
+#define _DBG_SEMA_COUNT_0(s, n) ((void) n)
+#define _DBG_SEMA_COUNT_1(s) ((void) 0)
+#define _DBG_SEMA_WAIT(s, n) ((void) n)
+#define _DBG_SEMA_SLEEP(s, n) ((void) n)
+#define _DBG_SEMA_COUNT_2(s) ((void) 0)
#endif
@@ -316,54 +426,44 @@ gdk_export ATOMIC_TYPE volatile GDKlocks
/* return 0 on success, -1 on failure to get the lock */
#define MT_lock_try(l) ((ATOMIC_CAS_int((l)->lock, 0, 1, dummy, dummy) == 0) -
1)
-#endif
-
-/*
- * @- MT Semaphore API
- */
-#if !defined(HAVE_PTHREAD_H) && defined(_MSC_VER)
-
-typedef HANDLE pthread_sema_t;
-gdk_export void pthread_sema_init(pthread_sema_t *s, int flag, int nresources);
-gdk_export void pthread_sema_destroy(pthread_sema_t *s);
-gdk_export void pthread_sema_up(pthread_sema_t *s);
-gdk_export void pthread_sema_down(pthread_sema_t *s);
-
-#elif defined(_AIX) || defined(__MACH__)
-
-typedef struct {
- int cnt;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-} pthread_sema_t;
-
-gdk_export void pthread_sema_init(pthread_sema_t *s, int flag, int nresources);
-gdk_export void pthread_sema_destroy(pthread_sema_t *s);
-gdk_export void pthread_sema_up(pthread_sema_t *s);
-gdk_export void pthread_sema_down(pthread_sema_t *s);
-
-#else
-
-#define pthread_sema_t sem_t
-#define pthread_sema_init sem_init
-#define pthread_sema_destroy sem_destroy
-#define pthread_sema_up sem_post
-#define pthread_sema_down(x) while(sem_wait(x))
+#define MT_sema_init(s, nr, n) \
+ do { \
+ (s)->lock = 0; \
_______________________________________________
checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list