diff options
Diffstat (limited to 'libglusterfs')
-rw-r--r-- | libglusterfs/src/syncop.c | 174 | ||||
-rw-r--r-- | libglusterfs/src/syncop.h | 26 |
2 files changed, 146 insertions, 54 deletions
diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c index 20d4d00561c..cb08b03d44b 100644 --- a/libglusterfs/src/syncop.c +++ b/libglusterfs/src/syncop.c @@ -827,16 +827,20 @@ syncenv_new (size_t stacksize, int procmin, int procmax) int -synclock_init (synclock_t *lock) +synclock_init (synclock_t *lock, lock_attr_t attr) { - if (!lock) - return -1; + if (!lock) + return -1; - pthread_cond_init (&lock->cond, 0); - lock->lock = 0; - INIT_LIST_HEAD (&lock->waitq); + pthread_cond_init (&lock->cond, 0); + lock->type = LOCK_NULL; + lock->owner = NULL; + lock->owner_tid = 0; + lock->lock = 0; + lock->attr = attr; + INIT_LIST_HEAD (&lock->waitq); - return pthread_mutex_init (&lock->guard, 0); + return pthread_mutex_init (&lock->guard, 0); } @@ -854,32 +858,70 @@ synclock_destroy (synclock_t *lock) static int __synclock_lock (struct synclock *lock) { - struct synctask *task = NULL; + struct synctask *task = NULL; - if (!lock) - return -1; + if (!lock) + return -1; - task = synctask_get (); + task = synctask_get (); - while (lock->lock) { - if (task) { - /* called within a synctask */ - list_add_tail (&task->waitq, &lock->waitq); + if (lock->lock && (lock->attr == SYNC_LOCK_RECURSIVE)) { + /*Recursive lock (if same owner requested for lock again then + *increment lock count and return success). + *Note:same number of unlocks required. + */ + switch (lock->type) { + case LOCK_TASK: + if (task == lock->owner) { + lock->lock++; + gf_log ("", GF_LOG_TRACE, "Recursive lock called by " + "sync task.owner= %p,lock=%d", lock->owner, lock->lock); + return 0; + } + break; + case LOCK_THREAD: + if (pthread_self () == lock->owner_tid) { + lock->lock++; + gf_log ("", GF_LOG_TRACE, "Recursive lock called by " + "thread ,owner=%u lock=%d", (unsigned int) lock->owner_tid, + lock->lock); + return 0; + } + break; + default: + gf_log ("", GF_LOG_CRITICAL, "unknown lock type"); + break; + } + } + + + while (lock->lock) { + if (task) { + /* called within a synctask */ + list_add_tail (&task->waitq, &lock->waitq); pthread_mutex_unlock (&lock->guard); synctask_yield (task); /* task is removed from waitq in unlock, * under lock->guard.*/ pthread_mutex_lock (&lock->guard); - } else { - /* called by a non-synctask */ - pthread_cond_wait (&lock->cond, &lock->guard); - } - } + } else { + /* called by a non-synctask */ + pthread_cond_wait (&lock->cond, &lock->guard); + } + } - lock->lock = _gf_true; - lock->owner = task; + if (task) { + lock->type = LOCK_TASK; + lock->owner = task; /* for synctask*/ - return 0; + } else { + lock->type = LOCK_THREAD; + lock->owner_tid = pthread_self (); /* for non-synctask */ + + } + lock->lock = 1; + + return 0; } @@ -925,37 +967,73 @@ unlock: static int __synclock_unlock (synclock_t *lock) { - struct synctask *task = NULL; - struct synctask *curr = NULL; + struct synctask *task = NULL; + struct synctask *curr = NULL; - if (!lock) - return -1; + if (!lock) + return -1; + + if (lock->lock == 0) { + gf_log ("", GF_LOG_CRITICAL, "Unlock called before lock "); + return -1; + } + curr = synctask_get (); + /*unlock should be called by lock owner + *i.e this will not allow the lock in nonsync task and unlock + * in sync task and vice-versa + */ + switch (lock->type) { + case LOCK_TASK: + if (curr == lock->owner) { + lock->lock--; + gf_log ("", GF_LOG_TRACE, "Unlock success %p, remaining" + " locks=%d", lock->owner, lock->lock); + } else { + gf_log ("", GF_LOG_WARNING, "Unlock called by %p, but" + " lock held by %p", curr, lock->owner); + } - curr = synctask_get (); + break; + case LOCK_THREAD: + if (pthread_self () == lock->owner_tid) { + lock->lock--; + gf_log ("", GF_LOG_TRACE, "Unlock success %u, remaining" + " locks=%d", (unsigned int)lock->owner_tid, lock->lock); + } else { + gf_log ("", GF_LOG_WARNING, "Unlock called by %u, but" + " lock held by %u", (unsigned int) pthread_self(), + (unsigned int) lock->owner_tid); + } - if (lock->owner != curr) { - /* warn ? */ - } + break; + default: + break; + } - lock->lock = _gf_false; - - /* There could be both synctasks and non synctasks - waiting (or none, or either). As a mid-approach - between maintaining too many waiting counters - at one extreme and a thundering herd on unlock - at the other, call a cond_signal (which wakes - one waiter) and first synctask waiter. So at - most we have two threads waking up to grab the - just released lock. - */ - pthread_cond_signal (&lock->cond); - if (!list_empty (&lock->waitq)) { - task = list_entry (lock->waitq.next, struct synctask, waitq); + if (lock->lock > 0) { + return 0; + } + lock->type = LOCK_NULL; + lock->owner = NULL; + lock->owner_tid = 0; + lock->lock = 0; + /* There could be both synctasks and non synctasks + waiting (or none, or either). As a mid-approach + between maintaining too many waiting counters + at one extreme and a thundering herd on unlock + at the other, call a cond_signal (which wakes + one waiter) and first synctask waiter. So at + most we have two threads waking up to grab the + just released lock. + */ + pthread_cond_signal (&lock->cond); + if (!list_empty (&lock->waitq)) { + task = list_entry (lock->waitq.next, struct synctask, waitq); list_del_init (&task->waitq); - synctask_wake (task); - } + synctask_wake (task); + } - return 0; + return 0; } diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h index 3a7798fa17e..f41706a9d37 100644 --- a/libglusterfs/src/syncop.h +++ b/libglusterfs/src/syncop.h @@ -114,12 +114,26 @@ struct syncenv { }; +typedef enum { + LOCK_NULL = 0, + LOCK_TASK, + LOCK_THREAD +} lock_type_t; + +typedef enum { + SYNC_LOCK_DEFAULT = 0, + SYNC_LOCK_RECURSIVE, /*it allows recursive locking*/ +} lock_attr_t; + struct synclock { - pthread_mutex_t guard; /* guard the remaining members, pair @cond */ - pthread_cond_t cond; /* waiting non-synctasks */ - struct list_head waitq; /* waiting synctasks */ - gf_boolean_t lock; /* _gf_true or _gf_false, lock status */ - struct synctask *owner; /* NULL if current owner is not a synctask */ + pthread_mutex_t guard; /* guard the remaining members, pair @cond */ + pthread_cond_t cond; /* waiting non-synctasks */ + struct list_head waitq; /* waiting synctasks */ + volatile int lock; /* true(non zero) or false(zero), lock status */ + lock_attr_t attr; + struct synctask *owner; /* NULL if current owner is not a synctask */ + pthread_t owner_tid; + lock_type_t type; }; typedef struct synclock synclock_t; @@ -336,7 +350,7 @@ syncop_create_frame (xlator_t *this) return frame; } -int synclock_init (synclock_t *lock); +int synclock_init (synclock_t *lock, lock_attr_t attr); int synclock_destroy (synclock_t *lock); int synclock_lock (synclock_t *lock); int synclock_trylock (synclock_t *lock); |