diff --git a/lock.c b/lock.c index 334d5e66..debfe43b 100644 --- a/lock.c +++ b/lock.c @@ -1,5 +1,31 @@ #include "uwsgi.h" +extern struct uwsgi_server uwsgi; + +static void uwsgi_register_lock(void *ptr, int rw) { + + struct uwsgi_lock_item *uli = uwsgi.registered_locks; + if (!uli) { + uwsgi.registered_locks = uwsgi_malloc(sizeof(struct uwsgi_lock_item)); + uwsgi.registered_locks->lock_ptr = ptr; + uwsgi.registered_locks->rw = rw; + uwsgi.registered_locks->next = NULL; + } + else { + while(uli) { + if (!uli->next) { + uli->next = uwsgi_malloc(sizeof(struct uwsgi_lock_item)); + uli->next->lock_ptr = ptr; + uli->rw = rw; + uli->next->next = NULL; + return; + } + uli = uli->next; + } + } + +} + #ifdef UWSGI_LOCK_USE_MUTEX @@ -123,31 +149,53 @@ void uwsgi_unlock(void *lock) { #ifdef UWSGI_LOCK_USE_OSX_SPINLOCK -#define UWSGI_LOCK_SIZE sizeof(OSSpinLock) -#define UWSGI_RWLOCK_SIZE sizeof(OSSpinLock) +#define UWSGI_LOCK_SIZE sizeof(OSSpinLock) + sizeof(pid_t) +#define UWSGI_RWLOCK_SIZE sizeof(OSSpinLock) + sizeof(pid_t) void uwsgi_lock_init(void *lock) { - memset(lock, 0, sizeof(OSSpinLock)); + memset(lock, 0, UWSGI_LOCK_SIZE); + uwsgi_register_lock(lock, 0); } void uwsgi_lock(void *lock) { OSSpinLockLock((OSSpinLock *) lock); + pid_t *pid = (pid_t *) lock + sizeof(OSSpinLock); + *pid = uwsgi.mypid; } void uwsgi_unlock(void *lock) { OSSpinLockUnlock((OSSpinLock *) lock); + pid_t *pid = (pid_t *) lock + sizeof(OSSpinLock); + *pid = 0; +} + +pid_t uwsgi_lock_check(void *lock) { + if (OSSpinLockTry((OSSpinLock *) lock)) { + OSSpinLockUnlock((OSSpinLock *) lock); + return 0; + } + pid_t *pid = (pid_t *) lock + sizeof(OSSpinLock); + return *pid; +} + +void uwsgi_rwlock_init(void *lock) { + memset(lock, 0, UWSGI_LOCK_SIZE); + uwsgi_register_lock(lock, 1); } -void uwsgi_rwlock_init(void *lock) { uwsgi_lock_init(lock) ;} void uwsgi_rlock(void *lock) { uwsgi_lock(lock);} void uwsgi_wlock(void *lock) { uwsgi_lock(lock);} + +pid_t uwsgi_rwlock_check(void *lock) { return uwsgi_lock_check(lock); } + void uwsgi_rwunlock(void *lock) { uwsgi_unlock(lock); } + #endif diff --git a/master.c b/master.c index 9d747171..99c13cd0 100644 --- a/master.c +++ b/master.c @@ -1538,11 +1538,33 @@ int master_loop(char **argv, char **environ) { // now check for lb pool - - continue; } + + if (diedpid > 0) { + // check for deadlocks first + struct uwsgi_lock_item *uli = uwsgi.registered_locks; + while(uli) { + pid_t locked_pid = 0; + if (uli->rw) { + locked_pid = uwsgi_rwlock_check(uli->lock_ptr); + } + else { + locked_pid = uwsgi_lock_check(uli->lock_ptr); + } + if (locked_pid == diedpid) { + uwsgi_log("[deadlock-detector] pid %d was holding lock %p\n", (int) diedpid, uli->lock_ptr); + if (uli->rw) { + uwsgi_rwunlock(uli->lock_ptr); + } + else { + uwsgi_unlock(uli->lock_ptr); + } + } + uli = uli->next; + } + } // reload gateways and daemons only on normal workflow if (!uwsgi.to_heaven && !uwsgi.to_hell) { diff --git a/uwsgi.h b/uwsgi.h index c98d0caa..33d5d303 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -289,6 +289,13 @@ struct uwsgi_string_list { struct uwsgi_string_list *next; }; +struct uwsgi_lock_item { + void *lock_ptr; + int rw; + struct uwsgi_lock_item *next; +}; + + struct uwsgi_dyn_dict { char *key; @@ -1414,6 +1421,8 @@ struct uwsgi_server { int cluster_fd; struct sockaddr_in mc_cluster_addr; + struct uwsgi_lock_item *registered_locks; + int check_cache; uint32_t cache_max_items; @@ -1972,10 +1981,12 @@ char *uwsgi_cache_get(char *, uint16_t, uint64_t *); uint32_t uwsgi_cache_exists(char *, uint16_t); void uwsgi_lock_init(void *); +pid_t uwsgi_lock_check(void *); void uwsgi_lock(void *); void uwsgi_unlock(void *); void uwsgi_rwlock_init(void *); +pid_t uwsgi_rwlock_check(void *); void uwsgi_rlock(void *); void uwsgi_wlock(void *); void uwsgi_rwunlock(void *);