blob: ae95c6d675f69ecde1d3025d8e03dfad54dc75b8 [file] [log] [blame]
John Park398c74a2018-10-20 21:17:39 -07001#ifndef AOS_IPC_LIB_SYNC_H_
2#define AOS_IPC_LIB_SYNC_H_
brians343bc112013-02-10 01:53:46 +00003
4#include <stdlib.h>
5#include <signal.h>
6#include <stdint.h>
Brian Silverman71c55c52014-08-19 14:31:59 -04007#include <stddef.h>
brians343bc112013-02-10 01:53:46 +00008
9#ifdef __cplusplus
10extern "C" {
11#endif // __cplusplus
12
13// TODO(brians) add client requests to make helgrind useful with this code
14// <http://www.valgrind.org/docs/manual/hg-manual.html#hg-manual.client-requests>
15// and <http://www.valgrind.org/docs/manual/drd-manual.html#drd-manual.clientreqs>
16// list the interesting ones
17
Brian Silvermandc1eb272014-08-19 14:25:59 -040018// Have to remember to align structs containing it (recursively) to sizeof(int).
Brian Silvermanaf221b82013-09-01 13:57:50 -070019// Valid initial values for use with futex_ functions are 0 (unset) and 1 (set).
brians343bc112013-02-10 01:53:46 +000020// The value should not be changed after multiple processes have started
21// accessing an instance except through the functions declared in this file.
Brian Silvermandc1eb272014-08-19 14:25:59 -040022typedef uint32_t aos_futex __attribute__((aligned(sizeof(int))));
brians343bc112013-02-10 01:53:46 +000023
Brian Silvermandc1eb272014-08-19 14:25:59 -040024// For use with the condition_ functions.
25// No initialization is necessary.
26typedef aos_futex aos_condition;
brians343bc112013-02-10 01:53:46 +000027
Brian Silvermandc1eb272014-08-19 14:25:59 -040028// For use with the mutex_ functions.
29// futex must be initialized to 0.
Brian Silverman71c55c52014-08-19 14:31:59 -040030// No initialization is necessary for next and previous.
31// Under ThreadSanitizer, pthread_mutex_init must be initialized to false.
Brian Silvermandc1eb272014-08-19 14:25:59 -040032// The recommended way to initialize one of these is by memset(3)ing the whole
33// thing to 0 or using C++ () initialization to avoid depending on the
34// implementation.
35struct aos_mutex {
Brian Silverman71c55c52014-08-19 14:31:59 -040036 // 2 links to get O(1) adds and removes.
37 // This is &next of another element.
38 // next (might) have stuff |ed into it to indicate PI futexes and might also
39 // have an offset (see SetRobustListOffset); previous is an actual pointer
40 // without any of that.
41 // next has to stay the first element of this structure.
42 uintptr_t next;
43 struct aos_mutex *previous;
Brian Silvermandc1eb272014-08-19 14:25:59 -040044 aos_futex futex;
Brian Silverman71c55c52014-08-19 14:31:59 -040045#ifdef AOS_SANITIZER_thread
46 // Internal pthread mutex which is kept in sync with the actual mutex so tsan
47 // can understand what's happening and help catch bugs.
48 pthread_mutex_t pthread_mutex;
49#ifndef __cplusplus
50 // TODO(brian): Remove this once the stupid C code is gone...
51#define bool uint8_t
52#endif
53 bool pthread_mutex_init;
54#ifndef __cplusplus
55#undef bool
56#endif
57#endif
Brian Silvermandc1eb272014-08-19 14:25:59 -040058};
59
60// The mutex_ functions are designed to be used as mutexes. A mutex can only be
Brian Silverman71c55c52014-08-19 14:31:59 -040061// unlocked from the same task which originally locked it. Also, if a task dies
62// while holding a mutex, the next person who locks it will be notified. After a
63// fork(2), any mutexes held will be held ONLY in the parent process. Attempting
64// to unlock them from the child will give errors.
65// Priority inheritance (aka priority inversion protection) is enabled.
Brian Silvermandc1eb272014-08-19 14:25:59 -040066
Brian Silverman71c55c52014-08-19 14:31:59 -040067// All of these return 1 if the previous owner died with it held, 2 if
Brian Silvermandc1eb272014-08-19 14:25:59 -040068// interrupted by a signal, 3 if timed out, or 4 if an optional lock fails. Some
69// of them (obviously) can never return some of those values.
Brian Silvermand41b4422013-09-01 14:02:33 -070070//
71// One of the highest priority processes blocked on a given mutex will be the
72// one to lock it when it is unlocked.
Brian Silvermandc1eb272014-08-19 14:25:59 -040073int mutex_lock(struct aos_mutex *m) __attribute__((warn_unused_result));
brians343bc112013-02-10 01:53:46 +000074// Returns 2 if it timed out or 1 if interrupted by a signal.
Brian Silvermandc1eb272014-08-19 14:25:59 -040075int mutex_lock_timeout(struct aos_mutex *m, const struct timespec *timeout)
76 __attribute__((warn_unused_result));
77// Ignores signals (retries until something other than getting a signal
78// happens).
79int mutex_grab(struct aos_mutex *m) __attribute__((warn_unused_result));
80// LOG(FATAL)s for multiple unlocking.
81void mutex_unlock(struct aos_mutex *m);
82// Does not block waiting for the mutex.
83int mutex_trylock(struct aos_mutex *m) __attribute__((warn_unused_result));
84#ifdef __cplusplus
85// Returns whether or not the mutex is locked by this thread.
86// There aren't very many valid uses for this function; the main ones are
87// checking mutexes as they are destroyed to catch problems with that early and
88// stack-based recursive mutex locking.
89bool mutex_islocked(const aos_mutex *m);
90#endif
brians343bc112013-02-10 01:53:46 +000091
Brian Silvermanaf221b82013-09-01 13:57:50 -070092// The futex_ functions are similar to the mutex_ ones but different.
brians343bc112013-02-10 01:53:46 +000093// They are designed for signalling when something happens (possibly to
Brian Silvermandc1eb272014-08-19 14:25:59 -040094// multiple listeners). A aos_futex manipulated with them can only be set or
95// unset. Also, they can be set/unset/waited on from any task independently of
96// who did something first and have no priority inversion protection.
97// They return -1 for other error (which will be in errno from futex(2)).
98// They have no spurious wakeups (because everybody always gets woken up).
Brian Silvermaneeb62ca2013-09-11 15:08:03 -070099//
Brian Silverman5f8c4922014-02-11 21:22:38 -0800100// Another name for this kind of synchronization mechanism is a "notification".
Brian Silvermandc1eb272014-08-19 14:25:59 -0400101// Python calls it an "event".
Brian Silverman5f8c4922014-02-11 21:22:38 -0800102//
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700103// They are different from the condition_ functions in that they do NOT work
104// correctly as standard condition variables. While it is possible to keep
105// track of the "condition" using the value part of the futex_* functions, the
106// obvious implementation has basically the same race condition that condition
107// variables are designed to prevent between somebody else grabbing the mutex
108// and changing whether it's set or not and the futex_ function changing the
Brian Silvermandc1eb272014-08-19 14:25:59 -0400109// futex's value. A futex is effectively a resettable condition variable with
110// the condition being "has it been set"; if you have some other condition (for
111// example messages are available to read on a queue), use the condition_
112// functions or there will be race conditions.
brians343bc112013-02-10 01:53:46 +0000113
Brian Silverman408511d2016-09-10 16:12:02 -0400114// Wait for the futex to be set. Will return immediately if it's already set
115// (after a syscall).
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700116// Returns 0 if successful or it was already set, 1 if interrupted by a signal,
Brian Silverman408511d2016-09-10 16:12:02 -0400117// or -1 with an error in errno. Can return 0 spuriously.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400118int futex_wait(aos_futex *m) __attribute__((warn_unused_result));
119// The same as futex_wait except returns 2 if it times out.
120int futex_wait_timeout(aos_futex *m, const struct timespec *timeout)
121 __attribute__((warn_unused_result));
122
Brian Silvermanaf221b82013-09-01 13:57:50 -0700123// Set the futex and wake up anybody waiting on it.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400124// Returns the number that were woken or -1 with an error in errno.
Brian Silvermand41b4422013-09-01 14:02:33 -0700125//
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700126// This will always wake up all waiters at the same time and set the value to 1.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400127int futex_set(aos_futex *m);
brians343bc112013-02-10 01:53:46 +0000128// Same as above except lets something other than 1 be used as the final value.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400129int futex_set_value(aos_futex *m, aos_futex value);
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700130// Unsets the futex (sets the value to 0).
brians343bc112013-02-10 01:53:46 +0000131// Returns 0 if it was set before and 1 if it wasn't.
Brian Silvermand41b4422013-09-01 14:02:33 -0700132// Can not fail.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400133int futex_unset(aos_futex *m);
Brian Silvermanaf221b82013-09-01 13:57:50 -0700134
135// The condition_ functions implement condition variable support. The API is
Brian Silverman797e71e2013-09-06 17:29:39 -0700136// similar to the pthreads api and works the same way. The same m argument must
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700137// be passed in for all calls to all of the condition_ functions with a given c.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400138// They do have the potential for spurious wakeups.
Brian Silvermanaf221b82013-09-01 13:57:50 -0700139
140// Wait for the condition variable to be signalled. m will be unlocked
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700141// atomically with actually starting to wait. m is guaranteed to be locked when
142// this function returns.
143// NOTE: The relocking of m is not atomic with stopping the actual wait and
144// other process(es) may lock (+unlock) the mutex first.
Brian Silverman71c55c52014-08-19 14:31:59 -0400145// Returns 0 on success or 1 if the previous owner died.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400146int condition_wait(aos_condition *c, struct aos_mutex *m)
147 __attribute__((warn_unused_result));
Brian Silvermanaf221b82013-09-01 13:57:50 -0700148// If any other processes are condition_waiting on c, wake 1 of them. Does not
Brian Silverman797e71e2013-09-06 17:29:39 -0700149// require m to be locked.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400150// NOTE: There is a small chance that this will wake more than just 1 waiter.
151void condition_signal(aos_condition *c, struct aos_mutex *m);
Brian Silverman797e71e2013-09-06 17:29:39 -0700152// Wakes all processes that are condition_waiting on c. Does not require m to be
153// locked.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400154void condition_broadcast(aos_condition *c, struct aos_mutex *m);
brians343bc112013-02-10 01:53:46 +0000155
156#ifdef __cplusplus
157}
Brian Silverman71c55c52014-08-19 14:31:59 -0400158
159namespace aos {
160namespace linux_code {
161namespace ipc_lib {
162
163typedef void (*FutexAccessorObserver)(void *address, bool write);
164
165// Set functions which get called before and after all futex operations.
166void SetFutexAccessorObservers(FutexAccessorObserver before,
167 FutexAccessorObserver after);
168
169// Set the offset to use for putting addresses into the robust list.
170// This is necessary to work around a kernel bug where it hangs when trying to
171// deal with a futex on the robust list when its memory has been changed to
172// read-only.
173void SetRobustListOffset(ptrdiff_t offset);
174
175// Returns true if there are any mutexes still locked by this task.
176// This is mainly useful for verifying tests don't mess up other ones by leaving
177// now-freed but still locked mutexes around.
178bool HaveLockedMutexes();
179
180} // namespace ipc_lib
181} // namespace linux_code
182} // namespace aos
183
brians343bc112013-02-10 01:53:46 +0000184#endif // __cplusplus
185
John Park398c74a2018-10-20 21:17:39 -0700186#endif // AOS_IPC_LIB_SYNC_H_