From d93e1fcea482f8348bb42171befea08466f8541f Mon Sep 17 00:00:00 2001
From: Benoit Germain Features:
-
- The underlying threading code can be compiled either towards Win32 API or Pthreads. Unfortunately, thread prioritization under Pthreads is a JOKE, - requiring OS specific tweaks and guessing undocumented behaviour. Other features should be portable to any modern platform. + The underlying threading code can be compiled either towards Win32 API or Pthreads. Unfortunately, thread prioritization under Pthreads + requires OS specific tweaks and guessing undocumented behaviour. Other features should be portable to any modern platform.
@@ -285,9 +285,9 @@
If mode is "soft", cancellation will only cause cancel_test() to return true, so that the lane can cleanup manually.
- If mode is "hard", waits for the request to be processed, or a timeout to occur. Linda operations detecting the cancellation request will raise a special cancellation error (meaning they won't return in that case).
+ If mode is "hard", waits for the request to be processed, or a timeout to occur. Linda operations detecting the cancellation request will raise a special cancellation error (meaning they won't return in that case).
wake_lane defaults to true, and timeout defaults to 0 if not specified.
@@ -1094,7 +1094,7 @@
Cancellation is tested before going to sleep in receive() or send() calls and after executing cancelstep Lua statements. A pending receive()or send() call is awakened.
- This means the execution of the lane will resume although the operation has not completed, to give the lane a chance to detect cancellation (even in the case the code waits on a linda with infinite timeout).
+ This means the execution of the lane will resume although the operation has not completed, to give the lane a chance to detect cancellation (even in the case the code waits on a Linda with infinite timeout).
The code should be able to handle this situation appropriately if required (in other words, it should gracefully handle the fact that it didn't receive the expected values).
@@ -1199,8 +1199,14 @@
Converting the Linda to a string will yield the provided name prefixed by "Linda: ".
- If opt_name is omitted, it will evaluate to an hexadecimal number uniquely representing that linda.
- If opt_name is "auto", Lanes will try to construct a name from the source location that called lanes.linda(). If that fails, the linda name will be "<unresolved>".
+ If opt_name is omitted, it will evaluate to an hexadecimal number uniquely representing that Linda.
+ If opt_name is "auto", Lanes will try to construct a name from the source location that called lanes.linda(). If that fails, the Linda name will be "<unresolved>".
Timeouts are given in seconds (>= 0, millisecond accuracy) or nil. Timeout can be omitted only if the first key is not a number (then it's equivalent to an infinite duration).
@@ -1229,7 +1235,7 @@
The send() and receive() methods use Linda keys as FIFO stacks (first in, first out).
By default, stack sizes are unlimited but limits can be enforced using the limit() method. This can be useful to balance execution speeds in a producer/consumer scenario. nil removes the limit.
A limit of 0 is allowed to block everything.
- If the key was full but the limit change added some room, limit() returns true and the linda is signalled so that send()-blocked threads are awakened.
+ If the key was full but the limit change added some room, limit() returns true and the Linda is signalled so that send()-blocked threads are awakened.
In batched mode, linda:receive() will raise an error if min_count < 1 or max_count < min_count.
- Hard cancellation will cause pending linda operations to abort execution of the lane through a cancellation error. This means that you have to install a finalizer in your lane if you want to run some code in that situation. + Hard cancellation will cause pending Linda operations to abort execution of the lane through a cancellation error. This means that you have to install a finalizer in your lane if you want to run some code in that situation.
@@ -1248,7 +1254,7 @@
If no data is provided after the key, send() raises an error.
- Also, if linda.null or lanes.null is sent as data in a linda, it will be read as a nil.
+ Also, if linda.null or lanes.null is sent as data in a Linda, it will be read as a nil.
@@ -1273,29 +1279,24 @@
- The table access methods are for accessing a slot without queuing or consuming. They can be used for making shared tables of storage among the lanes.
-
- Writing to a slot never blocks because it ignores the limit. It overwrites existing value and clears any possible queued entries.
-
- Reading doesn't block either because get() returns whatever is available (which can be nothing), up to the specified count.
-
+ The table access methods are for accessing a slot without queuing or consuming. They can be used for making shared tables of storage among the lanes.
+ Writing to a slot never blocks because it ignores the limit. It overwrites existing value and clears any possible queued entries.
+ Reading doesn't block either because get() returns whatever is available (which can be nothing), up to the specified count.
Table access and send()/receive() can be used together; reading a slot essentially peeks the next outcoming value of a queue.
- set() signals the linda for write if a value is stored. If nothing special happens, set() returns nothing.
-
- If the key was full but the new data count of the key after set() is below its limit, set() returns true and the linda is also signaled for read so that send()-blocked threads are awakened.
+ set() signals the Linda for write if a value is stored. If nothing special happens, set() returns nothing.
+ If the key was full but the new data count of the key after set() is below its limit, set() returns true and the Linda is also signaled for read so that send()-blocked threads are awakened.
- set() can write several values at the specified key, writing nil values is now possible, and clearing the contents at the specified key is done by not providing any value.
-
+ set() can write several values at the specified key, writing nil values is now possible, and clearing the contents at the specified key is done by not providing any value.
Also, get() can read several values at once. If the key contains no data, get() returns no value. This can be used to separate the case when reading stored nil values.
- Trying to send or receive data through a cancelled linda does nothing and returns lanes.cancel_error. + Trying to send or receive data through a cancelled Linda does nothing and returns lanes.cancel_error.
@@ -1303,14 +1304,10 @@ |
- Returns some information about the contents of the linda.
-
- If no key is specified, and the linda is empty, returns nothing.
-
- If no key is specified, and the linda is not empty, returns a table of key/count pairs that counts the number of items in each of the exiting keys of the linda. This count can be 0 if the key has been used but is empty.
-
- If a single key is specified, returns the number of pending items, or nothing if the key is unknown.
-
+ Returns some information about the contents of the Linda.
+ If no key is specified, and the Linda is empty, returns nothing.
+ If no key is specified, and the Linda is not empty, returns a table of key/count pairs that counts the number of items in each of the exiting keys of the Linda. This count can be 0 if the key has been used but is empty.
+ If a single key is specified, returns the number of pending items, or nothing if the key is unknown.
If more than one key is specified, return a table of key/count pairs for the known keys.
- Returns a table describing the full contents of a linda, or nil if the linda wasn't used yet.
- If Decoda support is enabled with HAVE_DECODA_SUPPORT(), linda metatable contain a __towatch special function that generates a similar table used for debug display.
+ Returns a table describing the full contents of a Linda, or nil if the Linda wasn't used yet.
+ If Decoda support is enabled with HAVE_DECODA_SUPPORT(), __towatch special function that generates a similar table used for debug display.
@@ -1328,30 +1325,22 @@ |
- Signals the linda so that lanes waiting for read, write, or both, wake up.
- All linda operations (including get() and set()) will return lanes.cancel_error as when the calling lane is soft-cancelled as long as the linda is marked as cancelled.
-
- "none" reset the linda's cancel status, but doesn't signal it.
-
- If not void, the lane's cancel status overrides the linda's cancel status.
+ Signals the Linda so that lanes waiting for read, write, or both, wake up.
+ All Linda operations (including get() and set()) will return lanes.cancel_error as when the calling lane is soft-cancelled as long as the Linda is marked as cancelled.
+ "none" reset the Linda's cancel status, but doesn't signal it.
+ If not void, the lane's cancel status overrides the Linda's cancel status.
- A linda is a gateway to read and write data inside some hidden Lua states, called keeper states. Lindas are hashed to a fixed number of keeper states, which are a locking entity.
-
- The data sent through a linda is stored inside the associated keeper state in a Lua table where each linda slot is the key to another table containing a FIFO for that slot.
-
- Each keeper state is associated with an OS mutex, to prevent concurrent access to the keeper state. The linda itself uses two signals to be made aware of operations occuring on it.
-
- Whenever Lua code reads from or writes to a linda, the mutex is acquired. If linda limits don't block the operation, it is fulfilled, then the mutex is released.
-
- If the linda has to block, the mutex is released and the OS thread sleeps, waiting for a linda operation to be signalled. When an operation occurs on the same linda, possibly fufilling the condition, or a timeout expires, the thread wakes up.
-
- If the thread is woken but the condition is not yet fulfilled, it goes back to sleep, until the timeout expires.
-
- When a lane is cancelled, the signal it is waiting on (if any) is signalled. In that case, the linda operation will return lanes.cancel_error.
+ A Linda is a gateway to read and write data inside some hidden Lua states, called keeper states. Lindas are hashed to a fixed number of keeper states, which are a locking entity.
+ The data sent through a Linda is stored inside the associated keeper state in a Lua table where each Linda slot is the key to another table containing a FIFO for that slot.
+ Each keeper state is associated with an OS mutex, to prevent concurrent access to the keeper state. The Linda itself uses two signals to be made aware of operations occuring on it.
+ Whenever Lua code reads from or writes to a Linda, the mutex is acquired. If Linda limits don't block the operation, it is fulfilled, then the mutex is released.
+ If the Linda has to block, the mutex is released and the OS thread sleeps, waiting for a Linda operation to be signalled. When an operation occurs on the same Linda, possibly fufilling the condition, or a timeout expires, the thread wakes up.
+ If the thread is woken but the condition is not yet fulfilled, it goes back to sleep, until the timeout expires.
+ When a lane is cancelled, the signal it is waiting on (if any) is signalled. In that case, the Linda operation will return lanes.cancel_error.
@@ -1372,7 +1361,7 @@
- Once a timer expires, the key is set with the current time (in seconds, same offset as os.time() but with millisecond accuracy). The key can be waited upon using the regular Linda :receive() method. + Once a timer expires, the key is set with the current time (in seconds, same offset as os.time() but with millisecond accuracy). The key can be waited upon using the regular Linda :receive() method.
@@ -1440,9 +1429,9 @@ On the other side, you need to use a common Linda for waiting for multiple keys.
- A very simple way of sleeping when nothing else is available. Is implemented by attempting to read some data in an unused channel of the internal linda used for timers (this linda exists even when timers aren't enabled).
- Default duration is 0, which should only cause a thread context switch.
+ A very simple way of sleeping when nothing else is available. Is implemented by attempting to read some data in an unused channel of the internal Linda used for timers (this Linda exists even when timers aren't enabled).
+ Default duration is 0, which should only cause a thread context switch.
Return values should always be nil, "timeout" (or nil, lanes.cancel_error in case of interruption).
- Returns the current value of the clock used by timers and lindas. + Returns the current value of the clock used by timers and Linda objects.
@@ -1497,7 +1486,7 @@ On the other side, you need to use a common Linda for waiting for multiple keys.
The generated function acquires M tokens from the N available, or releases them if the value is negative. The acquiring call will suspend the lane, if necessary. Use M=N=1 for a critical section lock (only one lane allowed to enter).
- When passsing "try" as second argument when acquiring, then lock_func operates on the linda with a timeout of 0 to emulate a TryLock() operation. If locking fails, lock_func returns false. "try" is ignored when releasing (as it it not expected to ever have to wait unless the acquisition/release pairs are not properly matched).
+ When passsing "try" as second argument when acquiring, then lock_func operates on the Linda with a timeout of 0 to emulate a TryLock() operation. If locking fails, lock_func returns false. "try" is ignored when releasing (as it it not expected to ever have to wait unless the acquisition/release pairs are not properly matched).
Upon successful lock/unlock, lock_func returns true (always the case when block-waiting for completion).
- The mechanism Lanes uses for sharing Linda handles between separate Lua states can be used for custom userdata as well. Here's what to do. + The mechanism Lanes uses for sharing Linda handles between separate Lua states can be used for custom userdata as well. Here's what to do.
- Deep userdata in transit inside keeper states (sent in a linda but not yet consumed) don't call deleteDeepObjectInternal and aren't considered by reference counting. The rationale is the following:
+ Deep userdata in transit inside Keeper states (sent in a Linda but not yet consumed) don't call deleteDeepObjectInternal and aren't considered by reference counting. The rationale is the following:
If some non-keeper state holds a deep userdata for some deep object, then even if the keeper collects its own deep userdata, it shouldn't be cleaned up since the refcount is not 0.
OTOH, if a keeper state holds the last deep userdata for some deep object, then no lane can do actual work with it. Deep userdata's factory() interface is never accessed from a keeper state.
- Therefore, Lanes can just call deleteDeepObjectInternal when the last non-keeper-held deep userdata is collected, as long as it doesn't do the same in a keeper state after that, since any remaining deep userdata in keeper states now hold stale pointers.
+ Therefore, Lanes can just call deleteDeepObjectInternal when the last non-keeper-held deep userdata is collected, as long as it doesn't do the same in a keeper state after that, since any remaining deep userdata in Keeper states now hold stale pointers.
@@ -1810,7 +1799,7 @@ static MyDeepFactory g_MyDeepFactory;
- The same benefits can be achieved by having a single worker lane spawn all the sublanes, and keep track of them. Communications to and from this lane can be handled via a Linda. + The same benefits can be achieved by having a single worker lane spawn all the sublanes, and keep track of them. Communications to and from this lane can be handled via a Linda.
@@ -1838,12 +1827,12 @@ static MyDeepFactory g_MyDeepFactory;