mirror of
https://github.com/OpenSolo/OpenSolo.git
synced 2025-04-30 14:44:31 +02:00
195 lines
5.0 KiB
C
195 lines
5.0 KiB
C
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include "util.h"
|
|
#include "mutex.h"
|
|
|
|
/*
|
|
* mutex_type_str - return string name of mutex type attribute (debug)
|
|
*/
|
|
static const char *mutex_type_str(int type)
|
|
{
|
|
switch (type) {
|
|
case PTHREAD_MUTEX_NORMAL:
|
|
return "PTHREAD_MUTEX_NORMAL";
|
|
case PTHREAD_MUTEX_ERRORCHECK:
|
|
return "PTHREAD_MUTEX_ERRORCHECK";
|
|
case PTHREAD_MUTEX_RECURSIVE:
|
|
return "PTHREAD_MUTEX_RECURSIVE";
|
|
/* PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL */
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
/*
|
|
* mutex_protocol_str - return string name of mutex protocol attribute (debug)
|
|
*/
|
|
static const char *mutex_protocol_str(int protocol)
|
|
{
|
|
switch (protocol) {
|
|
case PTHREAD_PRIO_NONE:
|
|
return "PTHREAD_PRIO_NONE";
|
|
case PTHREAD_PRIO_INHERIT:
|
|
return "PTHREAD_PRIO_INHERIT";
|
|
case PTHREAD_PRIO_PROTECT:
|
|
return "PTHREAD_PRIO_PROTECT";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
/*
|
|
* mutex_pshared_str - return string name of mutex pshared attribute (debug)
|
|
*/
|
|
static const char *mutex_pshared_str(int pshared)
|
|
{
|
|
switch (pshared) {
|
|
case PTHREAD_PROCESS_SHARED:
|
|
return "PTHREAD_PROCESS_SHARED";
|
|
case PTHREAD_PROCESS_PRIVATE:
|
|
return "PTHREAD_PROCESS_PRIVATE";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
/*
|
|
* mutex_attr_show - print mutex attributes to stdout (debug)
|
|
*/
|
|
void mutex_attr_show(const pthread_mutexattr_t *attr)
|
|
{
|
|
int rc;
|
|
int val;
|
|
|
|
printf("mutex attributes @ %10p:\n", attr);
|
|
|
|
rc = pthread_mutexattr_gettype(attr, &val);
|
|
if (rc != 0)
|
|
printf("ERROR %d returned from pthread_mutexattr_gettype\n", rc);
|
|
else
|
|
printf("type=%s\n", mutex_type_str(val));
|
|
|
|
rc = pthread_mutexattr_getprioceiling(attr, &val);
|
|
if (rc != 0)
|
|
printf("ERROR %d returned from pthread_mutexattr_getprioceiling\n", rc);
|
|
else
|
|
printf("prio_ceiling=%d\n", val);
|
|
|
|
rc = pthread_mutexattr_getprotocol(attr, &val);
|
|
if (rc != 0)
|
|
printf("ERROR %d returned from pthread_mutexattr_getprotocol\n", rc);
|
|
else
|
|
printf("protocol=%s\n", mutex_protocol_str(val));
|
|
|
|
rc = pthread_mutexattr_getpshared(attr, &val);
|
|
if (rc != 0)
|
|
printf("ERROR %d returned from pthread_mutexattr_getpshared\n", rc);
|
|
else
|
|
printf("pshared=%s\n", mutex_pshared_str(val));
|
|
}
|
|
|
|
/*
|
|
* mutex_init - initialize a mutex for use with realtime threads
|
|
*
|
|
* Default mutex attributes have a non-realtime priority ceiling, and do not
|
|
* have priority inversion enabled. This changes the defaults so the priority
|
|
* ceiling is the highest priority, priority inversion is enabled, and error
|
|
* checking it turned on.
|
|
*
|
|
* Attribute Default Setting Here
|
|
* --------------- -------------------------- --------------------------
|
|
* type PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_ERRORCHECK
|
|
* prio_ceiling 1 99
|
|
* protocol PTHREAD_PRIO_NONE PTHREAD_PRIO_INHERIT
|
|
* pshared PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE
|
|
*
|
|
* The priority specified for prio_ceiling is the SCHED_FIFO priority, i.e.
|
|
* 1 is lowest, 99 is highest.
|
|
*/
|
|
int mutex_init(pthread_mutex_t *mutex)
|
|
{
|
|
pthread_mutexattr_t attr;
|
|
int rc;
|
|
|
|
/* set up attributes */
|
|
|
|
rc = pthread_mutexattr_init(&attr);
|
|
if (rc != 0)
|
|
return rc;
|
|
|
|
/* mutex_attr_show(&attr); */
|
|
|
|
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
|
if (rc != 0)
|
|
return rc;
|
|
|
|
rc = pthread_mutexattr_setprioceiling(&attr, 99);
|
|
if (rc != 0)
|
|
return rc;
|
|
|
|
rc = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
|
|
if (rc != 0)
|
|
return rc;
|
|
|
|
rc = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
|
|
if (rc != 0)
|
|
return rc;
|
|
|
|
/* mutex_attr_show(&attr); */
|
|
|
|
rc = pthread_mutex_init(mutex, &attr);
|
|
if (rc != 0)
|
|
return rc;
|
|
|
|
return 0;
|
|
|
|
} /* mutex_init */
|
|
|
|
/*
|
|
* mutex_lock - lock mutex, keeping track of maximum block time
|
|
*
|
|
* If max_blocked_us is not NULL, measure how long it took to lock the
|
|
* mutex (how long we were blocked). Then, if the new blocked time was
|
|
* longer, update max_blocked_us; if the new blocked time was not
|
|
* longer, do not change max_blocked_us.
|
|
*
|
|
* To ignore how long the lock took, set max_blocked_us to NULL.
|
|
*
|
|
* To measure how long the lock took without regard to whether it is
|
|
* a new maximum, initialize *max_blocked_us to 0.
|
|
*/
|
|
int mutex_lock(pthread_mutex_t *mutex, uint64_t *max_blocked_us)
|
|
{
|
|
int rc;
|
|
uint64_t start_us;
|
|
uint64_t blocked_us;
|
|
|
|
if (max_blocked_us != NULL)
|
|
start_us = clock_gettime_us(CLOCK_MONOTONIC);
|
|
|
|
rc = pthread_mutex_lock(mutex);
|
|
|
|
if (rc == 0 && max_blocked_us != NULL) {
|
|
blocked_us = clock_gettime_us(CLOCK_MONOTONIC) - start_us;
|
|
if (*max_blocked_us < blocked_us)
|
|
*max_blocked_us = blocked_us;
|
|
}
|
|
|
|
return rc;
|
|
|
|
} /* mutex_lock */
|
|
|
|
/*
|
|
* mutex_unlock - unlock mutex
|
|
*
|
|
* Provided for symmetry with mutex_lock.
|
|
*/
|
|
int mutex_unlock(pthread_mutex_t *mutex)
|
|
{
|
|
|
|
return pthread_mutex_unlock(mutex);
|
|
|
|
} /* mutex_unlock */
|