diff options
Diffstat (limited to 'libglusterfs/src')
| -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);  | 
