| /* yarn.h -- generic interface for thread operations |
| * Copyright (C) 2008, 2011, 2012, 2015, 2018, 2019, 2020 Mark Adler |
| * Version 1.7 12 Apr 2020 Mark Adler |
| */ |
| |
| /* |
| This software is provided 'as-is', without any express or implied |
| warranty. In no event will the author be held liable for any damages |
| arising from the use of this software. |
| |
| Permission is granted to anyone to use this software for any purpose, |
| including commercial applications, and to alter it and redistribute it |
| freely, subject to the following restrictions: |
| |
| 1. The origin of this software must not be misrepresented; you must not |
| claim that you wrote the original software. If you use this software |
| in a product, an acknowledgment in the product documentation would be |
| appreciated but is not required. |
| 2. Altered source versions must be plainly marked as such, and must not be |
| misrepresented as being the original software. |
| 3. This notice may not be removed or altered from any source distribution. |
| |
| Mark Adler |
| [email protected] |
| */ |
| |
| /* Basic thread operations |
| |
| This interface isolates the local operating system implementation of threads |
| from the application in order to facilitate platform independent use of |
| threads. All of the implementation details are deliberately hidden. |
| |
| Assuming adequate system resources and proper use, none of these functions |
| can fail. As a result, any errors encountered will cause an exit() to be |
| executed, or the execution of your own optionally-provided abort function. |
| |
| These functions allow the simple launching and joining of threads, and the |
| locking of objects and synchronization of changes of objects. The latter is |
| implemented with a single lock type that contains an integer value. The |
| value can be ignored for simple exclusive access to an object, or the value |
| can be used to signal and wait for changes to an object. |
| |
| -- Arguments -- |
| |
| thread *thread; identifier for launched thread, used by join |
| void probe(void *); pointer to function "probe", run when thread starts |
| void *payload; single argument passed to the probe function |
| lock *lock; a lock with a value -- used for exclusive access to |
| an object and to synchronize threads waiting for |
| changes to an object |
| long val; value to set lock, increment lock, or wait for |
| int n; number of threads joined |
| |
| -- Thread functions -- |
| |
| thread = launch(probe, payload) - launch a thread -- exit via probe() return |
| join(thread) - join a thread and by joining end it, waiting for the thread |
| to exit if it hasn't already -- will free the resources allocated by |
| launch() (don't try to join the same thread more than once) |
| n = join_all() - join all threads launched by launch() that are not joined |
| yet and free the resources allocated by the launches, usually to clean |
| up when the thread processing is done -- join_all() returns an int with |
| the count of the number of threads joined (join_all() should only be |
| called from the main thread, and should only be called after any calls |
| of join() have completed) |
| |
| -- Lock functions -- |
| |
| lock = new_lock(val) - create a new lock with initial value val (lock is |
| created in the released state) |
| possess(lock) - acquire exclusive possession of a lock, waiting if necessary |
| twist(lock, [TO | BY], val) - set lock to or increment lock by val, signal |
| all threads waiting on this lock and then release the lock -- must |
| possess the lock before calling (twist releases, so don't do a |
| release() after a twist() on the same lock) |
| wait_for(lock, [TO_BE | NOT_TO_BE | TO_BE_MORE_THAN | TO_BE_LESS_THAN], val) |
| - wait on lock value to be, not to be, be greater than, or be less than |
| val -- must possess the lock before calling, will possess the lock on |
| return but the lock is released while waiting to permit other threads |
| to use twist() to change the value and signal the change (so make sure |
| that the object is in a usable state when waiting) |
| release(lock) - release a possessed lock (do not try to release a lock that |
| the current thread does not possess) |
| val = peek_lock(lock) - return the value of the lock (assumes that lock is |
| already possessed, no possess or release is done by peek_lock()) |
| free_lock(lock) - free the resources allocated by new_lock() (application |
| must assure that the lock is released before calling free_lock()) |
| |
| -- Memory allocation --- |
| |
| yarn_mem(better_malloc, better_free) - set the memory allocation and free |
| routines for use by the yarn routines where the supplied routines have |
| the same interface and operation as malloc() and free(), and may be |
| provided in order to supply thread-safe memory allocation routines or |
| for any other reason -- by default malloc() and free() will be used |
| |
| -- Error control -- |
| |
| yarn_prefix - a char pointer to a string that will be the prefix for any |
| error messages that these routines generate before exiting -- if not |
| changed by the application, "yarn" will be used |
| yarn_abort - an external function that will be executed when there is an |
| internal yarn error, due to out of memory or misuse -- this function |
| may exit to abort the application, or if it returns, the yarn error |
| handler will exit (set to NULL by default for no action) |
| */ |
| |
| extern char *yarn_prefix; |
| extern void (*yarn_abort)(int); |
| |
| void yarn_mem(void *(*)(size_t), void (*)(void *)); |
| |
| typedef struct thread_s thread; |
| thread *launch_(void (*)(void *), void *, char const *, long); |
| #define launch(a, b) launch_(a, b, __FILE__, __LINE__) |
| void join_(thread *, char const *, long); |
| #define join(a) join_(a, __FILE__, __LINE__) |
| int join_all_(char const *, long); |
| #define join_all() join_all_(__FILE__, __LINE__) |
| |
| typedef struct lock_s lock; |
| lock *new_lock_(long, char const *, long); |
| #define new_lock(a) new_lock_(a, __FILE__, __LINE__) |
| void possess_(lock *, char const *, long); |
| #define possess(a) possess_(a, __FILE__, __LINE__) |
| void release_(lock *, char const *, long); |
| #define release(a) release_(a, __FILE__, __LINE__) |
| enum twist_op { TO, BY }; |
| void twist_(lock *, enum twist_op, long, char const *, long); |
| #define twist(a, b, c) twist_(a, b, c, __FILE__, __LINE__) |
| enum wait_op { |
| TO_BE, /* or */ NOT_TO_BE, /* that is the question */ |
| TO_BE_MORE_THAN, TO_BE_LESS_THAN }; |
| void wait_for_(lock *, enum wait_op, long, char const *, long); |
| #define wait_for(a, b, c) wait_for_(a, b, c, __FILE__, __LINE__) |
| long peek_lock(lock *); |
| void free_lock_(lock *, char const *, long); |
| #define free_lock(a) free_lock_(a, __FILE__, __LINE__) |