Skip to content

Commit

Permalink
Added support for recursive mutexes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matt Raybuck authored and dcrowell77 committed Oct 29, 2018
1 parent 13d6fcf commit 0c5edba
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 28 deletions.
64 changes: 56 additions & 8 deletions src/include/sys/sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
/* */
Expand All @@ -27,13 +27,20 @@
#define __SYS_SYNC_H

#include <stdint.h>
#include <sys/task.h>

/**
* Mutex object type
*/
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;
Expand All @@ -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
Expand Down Expand Up @@ -103,38 +110,79 @@ 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
*/
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
Expand Down
128 changes: 117 additions & 11 deletions src/lib/sync.C
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -116,17 +118,54 @@ 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;
}

//-----------------------------------------------------------------------------

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;
}

Expand All @@ -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.
}
Expand All @@ -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
Expand All @@ -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;
Expand Down
16 changes: 14 additions & 2 deletions src/usr/targeting/common/xmltohb/xmltohb.pl
Original file line number Diff line number Diff line change
Expand Up @@ -4449,6 +4449,17 @@ sub unhexify {
return $val;
}

################################################################################
# Pack mutex
################################################################################

sub packMutex {
my $length = 24;
my $binaryData .= pack ("C".$length);

return $binaryData;
}

################################################################################
# Pack 8 byte value into a buffer using configured endianness
################################################################################
Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/usr/testcore/lib/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
# Contributors Listed Below - COPYRIGHT 2011,2016
# Contributors Listed Below - COPYRIGHT 2011,2018
# [+] International Business Machines Corp.
#
#
Expand All @@ -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

Expand Down

0 comments on commit 0c5edba

Please sign in to comment.