summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/sync.C128
1 files changed, 117 insertions, 11 deletions
diff --git a/src/lib/sync.C b/src/lib/sync.C
index 37367b219..c318856a1 100644
--- a/src/lib/sync.C
+++ b/src/lib/sync.C
@@ -5,7 +5,9 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* COPYRIGHT International Business Machines Corp. 2011,2014 */
+/* Contributors Listed Below - COPYRIGHT 2011,2018 */
+/* [+] International Business Machines Corp. */
+/* */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
@@ -116,9 +118,32 @@ void barrier_wait (barrier_t * i_barrier)
//-----------------------------------------------------------------------------
-void mutex_init(mutex_t * o_mutex)
+/**
+ * @fn mutex_init
+ * @brief Initialize a mutex object.
+ * @param[out] o_mutex the mutex
+ * @param[in] i_recursive indicate whether a mutex is recursive or not.
+ * @pre an uninitialized mutex object
+ * @post a valid mutex object
+ */
+void mutex_init(mutex_t * o_mutex, bool i_recursive)
{
o_mutex->iv_val = 0;
+ o_mutex->iv_owner = 0;
+ o_mutex->iv_ownerLockCount = 0;
+ o_mutex->iv_recursive = i_recursive;
+ return;
+}
+
+void mutex_init(mutex_t * o_mutex)
+{
+ mutex_init(o_mutex, false);
+ return;
+}
+
+void recursive_mutex_init(mutex_t * o_mutex)
+{
+ mutex_init(o_mutex, true);
return;
}
@@ -126,7 +151,21 @@ void mutex_init(mutex_t * o_mutex)
void mutex_destroy(mutex_t * i_mutex)
{
+ crit_assert(!i_mutex->iv_recursive);
+
i_mutex->iv_val = ~0;
+ i_mutex->iv_owner = 0;
+ i_mutex->iv_ownerLockCount = 0;
+ return;
+}
+
+void recursive_mutex_destroy(mutex_t * i_mutex)
+{
+ crit_assert(i_mutex->iv_recursive);
+
+ i_mutex->iv_val = ~0;
+ i_mutex->iv_owner = 0;
+ i_mutex->iv_ownerLockCount = 0;
return;
}
@@ -141,19 +180,21 @@ void mutex_lock(mutex_t * i_mutex)
// leaving (isync). Both __sync_val_compare_and_swap and
// __sync_lock_test_and_set have an implied isync.
- uint64_t l_count = __sync_val_compare_and_swap(&(i_mutex->iv_val),0,1);
+ crit_assert(!i_mutex->iv_recursive);
- if(unlikely(l_count != 0))
+ uint64_t l_lockStatus = __sync_val_compare_and_swap(&(i_mutex->iv_val),0,1);
+
+ if(unlikely(l_lockStatus != 0))
{
- if (likely(l_count != 2))
+ if(likely(l_lockStatus != 2))
{
- l_count = __sync_lock_test_and_set(&(i_mutex->iv_val), 2);
+ l_lockStatus = __sync_lock_test_and_set(&(i_mutex->iv_val), 2);
}
- while( l_count != 0 )
+ while(l_lockStatus != 0)
{
- futex_wait( &(i_mutex->iv_val), 2);
- l_count = __sync_lock_test_and_set(&(i_mutex->iv_val),2);
+ futex_wait(&(i_mutex->iv_val), 2);
+ l_lockStatus = __sync_lock_test_and_set(&(i_mutex->iv_val), 2);
// if more than one task gets out - one continues while
// the rest get blocked again.
}
@@ -174,8 +215,11 @@ void mutex_unlock(mutex_t * i_mutex)
// and futex_wake pair will appear globally ordered due to the
// context synchronizing nature of the 'sc' instruction.
- uint64_t l_count = __sync_fetch_and_sub(&(i_mutex->iv_val),1);
- if(unlikely(2 <= l_count))
+ crit_assert(!i_mutex->iv_recursive);
+
+ uint64_t l_lockStatus = __sync_fetch_and_sub(&(i_mutex->iv_val), 1);
+
+ if(unlikely(2 <= l_lockStatus))
{
i_mutex->iv_val = 0;
futex_wake(&(i_mutex->iv_val), 1); // wake one task
@@ -184,6 +228,68 @@ void mutex_unlock(mutex_t * i_mutex)
return;
}
+void recursive_mutex_lock(mutex_t * i_mutex)
+{
+ crit_assert(i_mutex->iv_recursive);
+
+ uint64_t l_lockStatus = __sync_val_compare_and_swap(&(i_mutex->iv_val),0,1);
+ do
+ {
+ if(unlikely(l_lockStatus != 0))
+ {
+ if (task_gettid() == i_mutex->iv_owner)
+ {
+ ++i_mutex->iv_ownerLockCount;
+ break;
+ }
+
+ if (likely(l_lockStatus != 2))
+ {
+ l_lockStatus = __sync_lock_test_and_set(&(i_mutex->iv_val), 2);
+ }
+
+ while( l_lockStatus != 0 )
+ {
+ futex_wait( &(i_mutex->iv_val), 2);
+ l_lockStatus = __sync_lock_test_and_set(&(i_mutex->iv_val),2);
+ // if more than one task gets out - one continues while
+ // the rest get blocked again.
+ }
+ }
+
+ i_mutex->iv_owner = task_gettid();
+ ++i_mutex->iv_ownerLockCount;
+
+ } while(0);
+
+ return;
+}
+
+void recursive_mutex_unlock(mutex_t * i_mutex)
+{
+ crit_assert(i_mutex->iv_recursive);
+
+ uint64_t l_lockStatus = 0;
+ if (i_mutex->iv_ownerLockCount <= 1)
+ {
+ i_mutex->iv_ownerLockCount = 0;
+ i_mutex->iv_owner = 0;
+ l_lockStatus = __sync_fetch_and_sub(&(i_mutex->iv_val),1);
+
+ if(unlikely(2 <= l_lockStatus))
+ {
+ i_mutex->iv_val = 0;
+ futex_wake(&(i_mutex->iv_val), 1); // wake one task
+ }
+ }
+ else
+ {
+ --i_mutex->iv_ownerLockCount;
+ }
+
+ return;
+}
+
void sync_cond_init(sync_cond_t * i_cond)
{
i_cond->mutex = NULL;
OpenPOWER on IntegriCloud