summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatt Raybuck <mraybuc@us.ibm.com>2018-10-24 07:54:39 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-10-29 10:43:57 -0500
commit0c5edba986eb543bc94ecb3514c40ca151dafc61 (patch)
tree157c85bcbd0d613615a8933cc1f0bb836d4381da /src
parent13d6fcf76a5fcab45d092fe39a807fbd70f4aff9 (diff)
downloadtalos-hostboot-0c5edba986eb543bc94ecb3514c40ca151dafc61.tar.gz
talos-hostboot-0c5edba986eb543bc94ecb3514c40ca151dafc61.zip
Added support for recursive mutexes
There was only support for non-recursive mutexes. This commit adds support for recursive mutexes and a new API for using them. Change-Id: I664c181af1633b05b8b2da6b1ff21b93a37cec28 RTC: 196793 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/67938 Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Reviewed-by: Ilya Smirnov <ismirno@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/sys/sync.h64
-rw-r--r--src/lib/sync.C128
-rwxr-xr-xsrc/usr/targeting/common/xmltohb/xmltohb.pl16
-rw-r--r--src/usr/testcore/lib/makefile4
-rw-r--r--src/usr/testcore/lib/synctest.H78
5 files changed, 262 insertions, 28 deletions
diff --git a/src/include/sys/sync.h b/src/include/sys/sync.h
index d56f8795b..2772c8807 100644
--- a/src/include/sys/sync.h
+++ b/src/include/sys/sync.h
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
+/* Contributors Listed Below - COPYRIGHT 2011,2018 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -27,6 +27,7 @@
#define __SYS_SYNC_H
#include <stdint.h>
+#include <sys/task.h>
/**
* Mutex object type
@@ -34,6 +35,12 @@
struct _futex_imp_t
{
uint64_t iv_val;
+ uint64_t iv_ownerLockCount;
+ tid_t iv_owner;
+ bool iv_recursive;
+
+ _futex_imp_t () : iv_val(0), iv_ownerLockCount(0),
+ iv_owner(0), iv_recursive(false) {}
};
typedef _futex_imp_t mutex_t;
@@ -51,7 +58,7 @@ struct _barrier_imp_t
typedef _barrier_imp_t barrier_t;
-#define MUTEX_INITIALIZER {0}
+#define MUTEX_INITIALIZER mutex_t()
/**
* Conditional variable types
@@ -103,25 +110,47 @@ void barrier_wait (barrier_t * i_barrier);
/**
* @fn mutex_init
- * @brief Initialize a mutex object
+ * @brief Initialize a non-recursive mutex object
* @param[out] o_mutex the mutex
* @pre an uninitialized mutex object
- * @post a valid mutex object
+ * @post a valid non-recursive mutex object
*/
void mutex_init(mutex_t * o_mutex);
/**
+ * @fn recursive_mutex_init
+ * @brief Initialize a recursive mutex object
+ * @param[out] o_mutex the mutex
+ * @pre an uninitialized mutex object
+ * @post a valid recursive mutex object
+ */
+void recursive_mutex_init(mutex_t * o_mutex);
+
+
+/**
* @fn mutex_destroy
- * @brief Destroy / uninitialize a mutex object.
- * @param[in] i_mutex - the mutex
+ * @brief Destroy / uninitialize a non-recursive mutex object. Code will assert
+ * if a recursive mutex is passed in.
+ * @param[in] i_mutex - the non-recursive mutex
* @note This does not free the memory associated with the object if the mutex
* was allocated off the heap.
*/
void mutex_destroy(mutex_t * i_mutex);
/**
+ * @fn recursive_mutex_destroy
+ * @brief Destroy / uninitialize a recursive mutex object. Code will assert if a
+ * non-recursive mutex is passed in.
+ * @param[in] i_mutex - the mutex
+ * @note This does not free the memory associated with the object if the mutex
+ * was allocated off the heap.
+ */
+void recursive_mutex_destroy(mutex_t * i_mutex);
+
+/**
* @fn mutex_lock
- * @brief Obtain a lock on a mutex
+ * @brief Obtain a lock on a mutex. If a recursive mutex is passed as the
+ * parameter the code will assert.
* @param[in] i_mutex - The mutex
* @post returns when this task has the lock
*/
@@ -129,13 +158,32 @@ void mutex_lock(mutex_t * i_mutex);
/**
* @fn mutex_unlock
- * @brief Release a lock on a mutex
+ * @brief Release a lock on a mutex. If a recursive mutex is passed as the
+ * parameter the code will assert.
* @param[in] i_mutex - the mutex
* @post mutex lock released
*/
void mutex_unlock(mutex_t * i_mutex);
/**
+ * @fn recursive_mutex_lock
+ * @brief Obtain a lock on a recursive mutex. If a non-recursive mutex is passed
+ * as the parameter the code will assert.
+ * @param[in] i_mutex - The mutex
+ * @post returns when this task has the lock
+ */
+void recursive_mutex_lock(mutex_t * i_mutex);
+
+/**
+ * @fn recursive_mutex_unlock
+ * @brief Release a lock on a recursive mutex. If a non-recursive mutex is
+ * passed as the parameter the code will assert.
+ * @param[in] i_mutex - A recursive mutex
+ * @post mutex lock released or mutex iv_ownerLockCount decremented.
+ */
+void recursive_mutex_unlock(mutex_t * i_mutex);
+
+/**
* @fn sync_cond_init
* @brief Initialize a condtional variable
* @param i_cond, The conditional variable
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;
diff --git a/src/usr/targeting/common/xmltohb/xmltohb.pl b/src/usr/targeting/common/xmltohb/xmltohb.pl
index c3f8c76f0..e92bf598e 100755
--- a/src/usr/targeting/common/xmltohb/xmltohb.pl
+++ b/src/usr/targeting/common/xmltohb/xmltohb.pl
@@ -4450,6 +4450,17 @@ sub unhexify {
}
################################################################################
+# Pack mutex
+################################################################################
+
+sub packMutex {
+ my $length = 24;
+ my $binaryData .= pack ("C".$length);
+
+ return $binaryData;
+}
+
+################################################################################
# Pack 8 byte value into a buffer using configured endianness
################################################################################
@@ -4868,7 +4879,7 @@ sub simpleTypeProperties {
$typesHoH{"uint32_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint32_t" , bytes => 4, bits => 32, default => \&defaultZero , alignment => 1, specialPolicies =>\&null, packfmt =>\&pack4byte};
$typesHoH{"uint64_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint64_t" , bytes => 8, bits => 64, default => \&defaultZero , alignment => 1, specialPolicies =>\&null, packfmt =>\&pack8byte};
$typesHoH{"enumeration"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 0, typeName => "XMLTOHB_USE_PARENT_ATTR_ID" , bytes => 0, bits => 0 , default => \&defaultEnum , alignment => 1, specialPolicies =>\&null, packfmt => "packEnumeration"};
- $typesHoH{"hbmutex"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 0, typeName => "mutex_t*" , bytes => 8, bits => 64, default => \&defaultZero , alignment => 8, specialPolicies =>\&enforceHbMutex, packfmt =>\&pack8byte};
+ $typesHoH{"hbmutex"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 0, typeName => "mutex_t*" , bytes => 24, bits => 192, default => \&defaultZero , alignment => 8, specialPolicies =>\&enforceHbMutex, packfmt =>\&packMutex};
$typesHoH{"Target_t"} = { supportsArray => 0, canBeHex => 1, complexTypeSupport => 0, typeName => "TARGETING::Target*" , bytes => 8, bits => 64, default => \&defaultZero , alignment => 8, specialPolicies =>\&null, packfmt =>\&pack8byte};
$typesHoH{"fspmutex"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 0, typeName => "util::Mutex*" , bytes => 8, bits => 64, default => \&defaultZero , alignment => 8, specialPolicies =>\&enforceFspMutex, packfmt =>\&pack8byte};
@@ -6367,7 +6378,8 @@ sub generateTargetingImage {
#skip the present target
next;
}
-# print Dumper($allAttributes);
+
+ #print Dumper($allAttributes);
# Update hash with any per-instance overrides, but only if that
# attribute has already been defined
diff --git a/src/usr/testcore/lib/makefile b/src/usr/testcore/lib/makefile
index a688b2a8f..ce80dc0df 100644
--- a/src/usr/testcore/lib/makefile
+++ b/src/usr/testcore/lib/makefile
@@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2011,2016
+# Contributors Listed Below - COPYRIGHT 2011,2018
# [+] International Business Machines Corp.
#
#
@@ -28,7 +28,7 @@ MODULE = testsyslib
#@TODO-RTC:151185-Turn enable all test cases
#TESTS = *.H
TESTS = stltest.H
-
+TESTS += synctest.H
SUBDIRS += runtime.d
diff --git a/src/usr/testcore/lib/synctest.H b/src/usr/testcore/lib/synctest.H
index c75e97db9..2662f020d 100644
--- a/src/usr/testcore/lib/synctest.H
+++ b/src/usr/testcore/lib/synctest.H
@@ -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. */
@@ -41,6 +43,49 @@ class SyncTest: public CxxTest::TestSuite
{
public:
+ void testRecursiveMutex(void)
+ {
+ int l_status = TASK_STATUS_EXITED_CLEAN;
+ // Note: These test cases are considered to have passed if no
+ // deadlocks occur.
+ // Case 1: Single thread locks recursive mutex three times in a row.
+ {
+ recursive_mutex_init(&mutex);
+
+ l_status = TASK_STATUS_EXITED_CLEAN;
+ tid_t l_task1 = task_create(entry_func, this);
+
+ if ((l_task1 != task_wait_tid(l_task1, &l_status, nullptr)) ||
+ (l_status == TASK_STATUS_EXITED_CLEAN))
+ {
+ TS_INFO("Thread ended.");
+ }
+ }
+
+ // Case 2: One thread grabs recursive mutex and another attempts to
+ // grab it (hangs) and then the first thread grabs it again
+ // without issue.
+ {
+ recursive_mutex_init(&mutex);
+
+ l_status = TASK_STATUS_EXITED_CLEAN;
+ tid_t l_task1 = task_create(entry_func, this);
+ tid_t l_task2 = task_create(entry_func, this);
+
+ if ((l_task2 != task_wait_tid(l_task2, &l_status, nullptr)) ||
+ (l_status == TASK_STATUS_EXITED_CLEAN))
+ {
+ TS_INFO("Thread ended.");
+ }
+
+ if ((l_task1 != task_wait_tid(l_task1, &l_status, nullptr)) ||
+ (l_status == TASK_STATUS_EXITED_CLEAN))
+ {
+ TS_INFO("Thread ended.");
+ }
+
+ }
+ }
void testMutex()
{
@@ -142,10 +187,6 @@ class SyncTest: public CxxTest::TestSuite
// test is success if it completes w/o hang
}
-
-
-
-
private:
enum
@@ -162,6 +203,33 @@ class SyncTest: public CxxTest::TestSuite
size_t counter;
+ static void* entry_func(void* i_p)
+ {
+ SyncTest* my = (SyncTest*) i_p;
+ mutex_t* myMutex = &(my->mutex);
+
+ // Call the recursive function.
+ recursive_func(myMutex, 2);
+
+ return nullptr;
+ }
+
+ static void recursive_func(mutex_t* mutex, int val)
+ {
+ TS_INFO("Attempting to enter Critical Section.");
+ recursive_mutex_lock(mutex);
+
+ TS_INFO("Accessing Critical Section.");
+ nanosleep(0, TEN_CTX_SWITCHES_NS);
+
+ if (val > 0)
+ {
+ recursive_func(mutex, val-1);
+ }
+
+ TS_INFO("Exiting Critical Section.");
+ recursive_mutex_unlock(mutex);
+ }
static void* func1(void * i_p)
{
OpenPOWER on IntegriCloud