Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p_mutex_*: Implement init/lock/unlock/etc: #162

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions include/pal_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ typedef p_ref_t p_event_t;
typedef p_ref_t p_mem_t;
typedef p_ref_t p_memptr_t;
typedef p_ref_t p_atom_t;
typedef p_ref_t p_mutex_t;
typedef p_ref_t p_mutex_attr_t;

typedef uint32_t * p_mutex_t;
typedef p_ref_t p_mutex_attr_t;

/*
***********************************************************************
Expand Down Expand Up @@ -172,7 +173,7 @@ int p_mutex_init(p_mutex_t *mp);
int p_mutex_lock(p_mutex_t *mp);

/*Try locking a mutex once*/
int p_mutex_trylock(p_mutex_t *mp);
int p_mutex_trylock(p_mutex_t *p);

/*Unlock a mutex*/
int p_mutex_unlock(p_mutex_t *mp);
Expand Down
28 changes: 26 additions & 2 deletions src/base/p_mutex_destroy.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,33 @@
#include "pal_base.h"
#include "pal_base_private.h"

/* Clean up and destroy a p_mutex_t
* @param mp A pointer to a p_mutex_t.
* @returns 0 on success,
* EINVAL when mp is NULL or uninitialized.
* EBUSY when the mutex has not been unlocked beforehand.
*/
int p_mutex_destroy(p_mutex_t *mp)
{
/*
* Conditions:
* mp must NOT be NULL (it is a pointer pointer!)
* *mp must NOT be NULL (that would mean it hasn't been initialized yet)
* **mp must NOT be Non-Zero (that would mean we're trying to unlock a locked mutex.)
*/

/*PLACE CODE HERE*/
return (0);
// Check if mp or *mp are null.
// If they are not null, check that the mutex is not locked.
if(mp == NULL || *mp == NULL) {
return EINVAL;
}
else if(**mp !=0) {
return EBUSY;
}

// at this point, the given value should be fine.
free(*mp);
// Be nice and clean the part of memory that we're touching.
*mp = NULL;
return 0;
}
27 changes: 22 additions & 5 deletions src/base/p_mutex_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,27 @@
#include "pal_base.h"
#include "pal_base_private.h"

int p_mutex_init(p_mutex_t *mp)
/*
* Initalize a mutex.
*
* This makes no attempt to make sure you're not clobbering an existing mutex.
* If for some reason you decide to pass this a locked, in-use mutex, it will
* happily trapse all over it and take your determinism right with it.
*
* This WILL make a cursory check to make sure malloc succeeded.
*
* @returns 0 on success, EINVAL if the p_mutex_t* is bad (NULL)
*
*/
int p_mutex_init(p_mutex_t * mp)
{

/*PLACE CODE HERE*/

return (0);
p_mutex_t tmp;
if(mp == NULL) {
return EINVAL;
}
*mp = malloc(sizeof(**mp));
if(*mp == NULL) {
return EINVAL;
}
**mp = 0;
}
41 changes: 39 additions & 2 deletions src/base/p_mutex_lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,46 @@
#include "pal_base.h"
#include "pal_base_private.h"

/* Take lock of a mutex.
*
* This will make a cursory check that you aren't passing NULL or a pointer
* to NULL in it. It won't check if you've been an idiot and passed in
* a uint32_t** because you aren't using the typedef.
*
* This is a blocking call. It will sit, chewing away at CPU time until it
* gets the mutex. It will constantly dereference the pointer you've handed
* it.
*
* If you destroy the mutex you are attempting to lock with this while the
* a call to this is going, you will segfault. If you don't segfault,
* it will still make no checks to see that you haven't quietly reallocated
* that bit of memory.
*
* @returns 0 on success, EINVAL if you pass it NULL before locking.
*/
int p_mutex_lock(p_mutex_t *mp)
{
/*PLACE CODE HERE*/

if(mp == NULL || *mp == NULL) {
return EINVAL;
}
/* We've got to avoid race conditions. Our solution to this is to spin
* until we can increment the mutex and make it 1, not 2.
* This works because our definition of "locked" is non-zero
* and our unlock is set to 0.
*
* When we lose the race, our mutex will be a value other than 1.
*
* When we enter the loop, we spin until **mp == 0
* When **mp == 0, we check if ++(**mp) == 1
* If that condition is true, we are safe: We won the race.
* If that condition is false, we lost the race: keep trying.
*/
do {
/* Spin while the lock is taken. */
while(**mp != 0) { ;; }
/* attempt to take the lock. If we lost the race
* we'll keep trying.
*/
} while( ++(**mp) != 1);
return (0);
}
27 changes: 23 additions & 4 deletions src/base/p_mutex_trylock.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,29 @@
#include "pal_base.h"
#include "pal_base_private.h"

/* attempts to consume the mutex mp
*
* This will quickly make an attempt to grab the mutex you are handing it.
* It makes a cursory check to see that you aren't passing in NULL or
* an uninitialized mutex.
*
* @param mp pointer to a p_mutex_t
* @returns 0 on success, EINVAL when passed NULL, EBUSY if you lose the race.
*/
int p_mutex_trylock(p_mutex_t *mp)
{

/*PLACE CODE HERE*/

return (0);
if( mp == NULL || *mp == NULL) {
return EINVAL;
}
if(**mp !=0 ) { return EBUSY; }
/* Try to take the mutex. If we won, **mp will be 1. If we lost,
* it'll be something different.
*
* There's one small caveat to this: If, by some magical means, you have
* the ability to make UINT_MAX attempts *simultaneously*
* you run the slight risk of overflowing.
*
* That's a lot of attempts, though.
*/
return ( ++(**mp) == 1 ? 0 : EBUSY );
}
21 changes: 17 additions & 4 deletions src/base/p_mutex_unlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,23 @@
#include "pal_base.h"
#include "pal_base_private.h"

/*
* Unlock a mutex.
*
* This makes a cursory check to see if you're passing it a bad value.
*
* @param mp the mutex to unlock
* @returns 0 on success, EINVAL if mp is NULL or uninitialized.
*
*/
int p_mutex_unlock(p_mutex_t *mp)
{

/*PLACE CODE HERE*/

return (0);
if(mp == NULL || *mp == NULL) {
return EINVAL;
}
else
{
**mp = 0;
return (0);
}
}
7 changes: 2 additions & 5 deletions src/base/pal_base_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,11 @@ struct p_event

struct p_atom_u32
{
uint32_t mutex; // resource mutex
p_mutex_t mutex; // resource mutex
uint32_t var; // atomic variable
};

struct p_mutex
{
uint32_t mutex; // mutex
};


/*
***********************************************************************
Expand Down