diff --git a/include/pthread.h b/include/pthread.h index 214ad454fe9..30c96bab9c8 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -143,12 +143,42 @@ #define PTHREAD_PRIO_INHERIT SEM_PRIO_INHERIT #define PTHREAD_PRIO_PROTECT SEM_PRIO_PROTECT +/* Values for robust argument of pthread_mutexattr_get/setrobust + * + * PTHREAD_MUTEX_STALLED - No special actions are taken if the owner of the + * mutex is terminated while holding the mutex lock. This can lead to + * deadlocks if no other thread can unlock the mutex. This is the standard + * default value (NuttX permits you to override that default behavior + * with a configuration option). + * + * PTHREAD_MUTEX_ROBUST - If the process containing the owning thread of a + * robust mutex terminates while holding the mutex lock, the next thread + * that acquires the mutex will be notified about the termination by the + * return value EOWNERDEAD from the locking function. If the owning thread + * of a robust mutex terminates while holding the mutex lock, the next + * thread that attempts to acquire the mutex may be notified about the + * termination by the return value EOWNERDEAD. The notified thread can + * then attempt to make the state protected by the mutex consistent again, + * and if successful can mark the mutex state as consistent by calling + * pthread_mutex_consistent(). After a subsequent successful call to + * pthread_mutex_unlock(), the mutex lock will be released and can be used + * normally by other threads. If the mutex is unlocked without a call to + * pthread_mutex_consistent(), it will be in a permanently unusable state + * and all attempts to lock the mutex will fail with the error + * ENOTRECOVERABLE. The only permissible operation on such a mutex is + * pthread_mutex_destroy(). + */ + +#define PTHREAD_MUTEX_STALLED 0 +#define PTHREAD_MUTEX_ROBUST 1 + /* Values for struct pthread_mutex_s flags. These are non-standard and * intended only for internal use within the OS. */ -#define _PTHREAD_MFLAGS_INCONSISTENT (1 << 0) /* Mutex is in an inconsistent state */ -#define _PTHREAD_MFLAGS_NOTRECOVRABLE (1 << 1) /* Inconsistent mutex has been unlocked */ +#define _PTHREAD_MFLAGS_ROBUST (1 << 0) /* Robust (NORMAL) mutex */ +#define _PTHREAD_MFLAGS_INCONSISTENT (1 << 1) /* Mutex is in an inconsistent state */ +#define _PTHREAD_MFLAGS_NOTRECOVRABLE (1 << 2) /* Inconsistent mutex has been unlocked */ /* Definitions to map some non-standard, BSD thread management interfaces to * the non-standard Linux-like prctl() interface. Since these are simple @@ -226,12 +256,15 @@ typedef struct pthread_cond_s pthread_cond_t; struct pthread_mutexattr_s { - uint8_t pshared; /* PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED */ + uint8_t pshared : 1; /* PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED */ #ifdef CONFIG_PRIORITY_INHERITANCE - uint8_t proto; /* See PTHREAD_PRIO_* definitions */ + uint8_t proto : 2; /* See PTHREAD_PRIO_* definitions */ #endif #ifdef CONFIG_MUTEX_TYPES - uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */ + uint8_t type : 2; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */ +#endif +#ifdef CONFIG_PTHREAD_MUTEX_BOTH + uint8_t robust : 1; /* PTHREAD_MUTEX_STALLED or PTHREAD_MUTEX_ROBUST */ #endif }; @@ -432,6 +465,10 @@ int pthread_mutexattr_getprotocol(FAR const pthread_mutexattr_t *attr, FAR int *protocol); int pthread_mutexattr_setprotocol(FAR pthread_mutexattr_t *attr, int protocol); +int pthread_mutexattr_getrobust(FAR const pthread_mutexattr_t *attr, + FAR int *robust); +int pthread_mutexattr_setrobust(FAR pthread_mutexattr_t *attr, + int robust); /* The following routines create, delete, lock and unlock mutexes. */ diff --git a/libc/pthread/Make.defs b/libc/pthread/Make.defs index 089845d8f7e..b8be2927d2f 100644 --- a/libc/pthread/Make.defs +++ b/libc/pthread/Make.defs @@ -49,6 +49,7 @@ CSRCS += pthread_mutexattr_init.c pthread_mutexattr_destroy.c CSRCS += pthread_mutexattr_getpshared.c pthread_mutexattr_setpshared.c CSRCS += pthread_mutexattr_setprotocol.c pthread_mutexattr_getprotocol.c CSRCS += pthread_mutexattr_settype.c pthread_mutexattr_gettype.c +CSRCS += pthread_mutexattr_setrobust.c pthread_mutexattr_getrobust.c CSRCS += pthread_setcancelstate.c pthread_setcanceltype.c CSRCS += pthread_testcancel.c diff --git a/libc/pthread/pthread_mutexattr_init.c b/libc/pthread/pthread_mutexattr_init.c index f1b6bca9c7c..de6183e56c3 100644 --- a/libc/pthread/pthread_mutexattr_init.c +++ b/libc/pthread/pthread_mutexattr_init.c @@ -76,11 +76,21 @@ int pthread_mutexattr_init(FAR pthread_mutexattr_t *attr) else { attr->pshared = 0; + #ifdef CONFIG_PRIORITY_INHERITANCE attr->proto = SEM_PRIO_INHERIT; #endif + #ifdef CONFIG_MUTEX_TYPES attr->type = PTHREAD_MUTEX_DEFAULT; +#endif + +#ifdef CONFIG_PTHREAD_MUTEX_BOTH +#ifdef CONFIG_PTHREAD_MUTEX_DEFAULT_UNSAFE + attr->robust = PTHREAD_MUTEX_STALLED; +#else + attr->robust = PTHREAD_MUTEX_ROBUST; +#endif #endif } diff --git a/sched/Kconfig b/sched/Kconfig index 369e9ac7cd7..60183e67d2c 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -549,7 +549,29 @@ choice software you may be porting or, perhaps, if you are trying to minimize footprint. -endchoice # thread mutex robustness + config PTHREAD_MUTEX_BOTH + bool "Both robust and unsafe mutexes" + ---help--- + Support both forms of NORMAL mutexes. + +endchoice # pthread mutex robustness + +choice + prompt "Default NORMAL mutex robustness" + default PTHREAD_MUTEX_DEFAULT_ROBUST + depends on PTHREAD_MUTEX_BOTH + + config PTHREAD_MUTEX_DEFAULT_ROBUST + bool "Robust default" + ---help--- + The default is robust NORMAL mutexes (non-standard) + + config PTHREAD_MUTEX_DEFAULT_UNSAFE + bool "Unsafe default" + ---help--- + The default is traditional unsafe NORMAL mutexes (standard) + +endchoice # Default NORMAL mutex robustness config NPTHREAD_KEYS int "Maximum number of pthread keys" diff --git a/sched/pthread/pthread_mutexinit.c b/sched/pthread/pthread_mutexinit.c index 46c9e67356b..e6abe32900f 100644 --- a/sched/pthread/pthread_mutexinit.c +++ b/sched/pthread/pthread_mutexinit.c @@ -77,6 +77,13 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex, #endif #ifdef CONFIG_PRIORITY_INHERITANCE uint8_t proto = PTHREAD_PRIO_INHERIT; +#endif +#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE +#ifdef CONFIG_PTHREAD_MUTEX_DEFAULT_UNSAFE + uint8_t robust = PTHREAD_MUTEX_STALLED; +#else + uint8_t robust = PTHREAD_MUTEX_ROBUST; +#endif #endif int ret = OK; int status; @@ -99,6 +106,9 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex, #endif #ifdef CONFIG_MUTEX_TYPES type = attr->type; +#endif +#ifdef CONFIG_PTHREAD_MUTEX_BOTH + robust = attr->robust; #endif } @@ -128,7 +138,7 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex, /* Initial internal fields of the mutex */ mutex->flink = NULL; - mutex->flags = 0; + mutex->flags = (robust == PTHREAD_MUTEX_ROBUST ? _PTHREAD_MFLAGS_ROBUST : 0); #endif #ifdef CONFIG_MUTEX_TYPES