Dees_Troy | 51a0e82 | 2012-09-05 15:24:24 -0400 | [diff] [blame] | 1 | /* yarn.h -- generic interface for thread operations |
Dees_Troy | 3bde123 | 2012-09-22 08:10:28 -0400 | [diff] [blame^] | 2 | * Copyright (C) 2008, 2011 Mark Adler |
| 3 | * Version 1.3 13 Jan 2012 Mark Adler |
Dees_Troy | 51a0e82 | 2012-09-05 15:24:24 -0400 | [diff] [blame] | 4 | */ |
| 5 | |
| 6 | /* |
| 7 | This software is provided 'as-is', without any express or implied |
| 8 | warranty. In no event will the author be held liable for any damages |
| 9 | arising from the use of this software. |
| 10 | |
| 11 | Permission is granted to anyone to use this software for any purpose, |
| 12 | including commercial applications, and to alter it and redistribute it |
| 13 | freely, subject to the following restrictions: |
| 14 | |
| 15 | 1. The origin of this software must not be misrepresented; you must not |
| 16 | claim that you wrote the original software. If you use this software |
| 17 | in a product, an acknowledgment in the product documentation would be |
| 18 | appreciated but is not required. |
| 19 | 2. Altered source versions must be plainly marked as such, and must not be |
| 20 | misrepresented as being the original software. |
| 21 | 3. This notice may not be removed or altered from any source distribution. |
| 22 | |
| 23 | Mark Adler |
| 24 | madler@alumni.caltech.edu |
| 25 | */ |
| 26 | |
| 27 | /* Basic thread operations |
| 28 | |
| 29 | This interface isolates the local operating system implementation of threads |
| 30 | from the application in order to facilitate platform independent use of |
| 31 | threads. All of the implementation details are deliberately hidden. |
| 32 | |
| 33 | Assuming adequate system resources and proper use, none of these functions |
| 34 | can fail. As a result, any errors encountered will cause an exit() to be |
| 35 | executed. |
| 36 | |
| 37 | These functions allow the simple launching and joining of threads, and the |
| 38 | locking of objects and synchronization of changes of objects. The latter is |
| 39 | implemented with a single lock type that contains an integer value. The |
| 40 | value can be ignored for simple exclusive access to an object, or the value |
| 41 | can be used to signal and wait for changes to an object. |
| 42 | |
| 43 | -- Arguments -- |
| 44 | |
| 45 | thread *thread; identifier for launched thread, used by join |
| 46 | void probe(void *); pointer to function "probe", run when thread starts |
| 47 | void *payload; single argument passed to the probe function |
| 48 | lock *lock; a lock with a value -- used for exclusive access to |
| 49 | an object and to synchronize threads waiting for |
| 50 | changes to an object |
| 51 | long val; value to set lock, increment lock, or wait for |
| 52 | int n; number of threads joined |
| 53 | |
| 54 | -- Thread functions -- |
| 55 | |
| 56 | thread = launch(probe, payload) - launch a thread -- exit via probe() return |
| 57 | join(thread) - join a thread and by joining end it, waiting for the thread |
| 58 | to exit if it hasn't already -- will free the resources allocated by |
| 59 | launch() (don't try to join the same thread more than once) |
| 60 | n = join_all() - join all threads launched by launch() that are not joined |
| 61 | yet and free the resources allocated by the launches, usually to clean |
| 62 | up when the thread processing is done -- join_all() returns an int with |
| 63 | the count of the number of threads joined (join_all() should only be |
| 64 | called from the main thread, and should only be called after any calls |
| 65 | of join() have completed) |
| 66 | destruct(thread) - terminate the thread in mid-execution and join it |
| 67 | (depending on the implementation, the termination may not be immediate, |
| 68 | but may wait for the thread to execute certain thread or file i/o |
| 69 | operations) |
| 70 | |
| 71 | -- Lock functions -- |
| 72 | |
| 73 | lock = new_lock(val) - create a new lock with initial value val (lock is |
| 74 | created in the released state) |
| 75 | possess(lock) - acquire exclusive possession of a lock, waiting if necessary |
| 76 | twist(lock, [TO | BY], val) - set lock to or increment lock by val, signal |
| 77 | all threads waiting on this lock and then release the lock -- must |
| 78 | possess the lock before calling (twist releases, so don't do a |
| 79 | release() after a twist() on the same lock) |
| 80 | wait_for(lock, [TO_BE | NOT_TO_BE | TO_BE_MORE_THAN | TO_BE_LESS_THAN], val) |
| 81 | - wait on lock value to be, not to be, be greater than, or be less than |
| 82 | val -- must possess the lock before calling, will possess the lock on |
| 83 | return but the lock is released while waiting to permit other threads |
| 84 | to use twist() to change the value and signal the change (so make sure |
| 85 | that the object is in a usable state when waiting) |
| 86 | release(lock) - release a possessed lock (do not try to release a lock that |
| 87 | the current thread does not possess) |
| 88 | val = peek_lock(lock) - return the value of the lock (assumes that lock is |
| 89 | already possessed, no possess or release is done by peek_lock()) |
| 90 | free_lock(lock) - free the resources allocated by new_lock() (application |
| 91 | must assure that the lock is released before calling free_lock()) |
| 92 | |
| 93 | -- Memory allocation --- |
| 94 | |
| 95 | yarn_mem(better_malloc, better_free) - set the memory allocation and free |
| 96 | routines for use by the yarn routines where the supplied routines have |
| 97 | the same interface and operation as malloc() and free(), and may be |
| 98 | provided in order to supply thread-safe memory allocation routines or |
| 99 | for any other reason -- by default malloc() and free() will be used |
| 100 | |
| 101 | -- Error control -- |
| 102 | |
Dees_Troy | 3bde123 | 2012-09-22 08:10:28 -0400 | [diff] [blame^] | 103 | yarn_prefix - a char pointer to a string that will be the prefix for any |
| 104 | error messages that these routines generate before exiting -- if not |
| 105 | changed by the application, "yarn" will be used |
Dees_Troy | 51a0e82 | 2012-09-05 15:24:24 -0400 | [diff] [blame] | 106 | yarn_abort - an external function that will be executed when there is an |
| 107 | internal yarn error, due to out of memory or misuse -- this function |
| 108 | may exit to abort the application, or if it returns, the yarn error |
| 109 | handler will exit (set to NULL by default for no action) |
| 110 | */ |
| 111 | |
| 112 | extern char *yarn_prefix; |
| 113 | extern void (*yarn_abort)(int); |
| 114 | |
| 115 | void yarn_mem(void *(*)(size_t), void (*)(void *)); |
| 116 | |
| 117 | typedef struct thread_s thread; |
| 118 | thread *launch(void (*)(void *), void *); |
| 119 | void join(thread *); |
| 120 | int join_all(void); |
| 121 | void destruct(thread *); |
| 122 | |
| 123 | typedef struct lock_s lock; |
| 124 | lock *new_lock(long); |
| 125 | void possess(lock *); |
| 126 | void release(lock *); |
| 127 | enum twist_op { TO, BY }; |
| 128 | void twist(lock *, enum twist_op, long); |
| 129 | enum wait_op { |
| 130 | TO_BE, /* or */ NOT_TO_BE, /* that is the question */ |
| 131 | TO_BE_MORE_THAN, TO_BE_LESS_THAN }; |
| 132 | void wait_for(lock *, enum wait_op, long); |
| 133 | long peek_lock(lock *); |
| 134 | void free_lock(lock *); |