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 checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list