Welcome
» NERWous C
» Mel
Mel Read Attributes
Let's consider these two mel read statements:
Reader Mode
A mel read statement is not only about accessing the remote mel element, but also about waiting for the task's turn to access in one of the mel reader's queues, and then waiting again for the mel element to have a filled slot, and finally removing the read item from the mel buffer. The last action prevents the read value to be read again by another task. These are the mel read conditions to be formalized later.
Asynchronous Mode
Using the asynchronous mode, the task can continue doing other things while the mel read conditions are being met. When the task finally needs the read value, it can check if a value has been successfully read. We will explore asynchronous reads in a later section.
Readonly Mode
It is possible to read the mel value and leave it back in the mel buffer for other reader tasks by using the
Mel Reader Mode
A mel read operation accesses a mel variable at the reader's end of the mel buffer. For example to read the mel variable
Mel Read Waits
Let's start with a simple Producer/Consumer example with a focus on the Consumer side to explore the mel read access:
The purpose of the
Mel Read Process
This is the behind-the-scene process for the statement
Mel Read Conditions
As a summary, the following conditions must be met before a task can read out a mel value:
The second condition concerns the
The third condition is relevant when there are other tasks already in the readers' queue. All tasks join a readers' queue at the bottom, and moves up the queue. Only the task at the top of a readers' queue can retrieve the mel value.
The fourth condition is relevant when there are multiple readers' queues vying for access to the same mel element. A queue with a higher priority is granted access to the mel element before lower priority queues.
The fifth condition checks if the mel element is empty. The reader task must wait for a writer task to deposit a value to the mel buffer before it can read it.
The sixth condition is relevant when the reader task finds a value already in the mel element but this value is already read due to a previous read access. This happens when we repeatedly do a readonly access to a mel, and since a readonly access does not remove the mel value, subsequent readonly accesses may see a stale value. Staleness should not happen for normal reads due to the removal of the mel value. However the staleness check is included as part of the read conditions as an additional step to insure integrity, especially in heterogeneous system where different parts running at different speed and reliability, could introduce unexpected inconsistencies. When staleness is discovered, the task must wait first for another reader task to read out that stale value, and then for a writer task to deposit a fresh value to the mel buffer.
Mel Properties On Reads
Mel properties belong to mel variables. A mel variable represents a session between a task and the mel element due to a mel operation. Unlike the remote mel, the mel variable is resident to the task. For the mel read operation, properties are set on entry, and on success or failure.
On Read Entry
This table summarizes the properties settings on entry of a mel read operation:
On Read Success
When a mel read operation is successful, the properties of the mel variable are set as follows:
On Read Failure
When a mel read operation fails, the properties of the mel variable are set as follows:
Agent Mel Property
The reader mode that has been discussed so far, is the default mode to read from mel elements. There is another mode which is the mel asynchronous read. Before we explore this mode, let's get introduced to the <agent> mel property.
The <agent> property is one of the IN properties. On entry to any mel operation (including the mel read operation), CHAOS initializes the <agent> property of the local mel variable with a value to indicate the execution entity that will run the mel operation. The <agent> property has the following values:
The <agent> property is set up differently depending on the reading mode used:
The <agent> property is only changed on entry of a mel operation. Afterwards it reflects the execution agent of the last mel operation.
Mel Asynchronous Reads
With the default reader mode, the task initiates the mel read operation and does the mel wait. We now introduce the asynchronous mode where the task initiates the mel read operation but has the CHAOS runtime does the mel wait for it. The task can use this time to do something else more productive.
Asynchronous Read Basic
Let's start with a
Let's now modify
The
On the other hand, CHAOS may still be in the mel waiting. The check for NERW_ERROR_NONE in
In fact, the check for NERW_ERROR_NONE in
The mel read request
The above
Asynchronous Read With Error Checking
An asynchronous read operation can be invoked with other mel read attributes. Let's explore the behind-the-scene process of an asynchronous read with timeout and <error> property checking.
Asynchronous Read With Exceptions
A drawback with the asynchronous read with error checking is that once the
The asynchronous mel read can fail, due to timeout, mel closure or other causes. If this ever happens, CHAOS will set the <error> and <why> properties of the mel variable, per On Read Failure settings. However CHAOS will not interrupt the
The
Things are different with the <TIMEDOUT> handler. If the asynchronous mel read has timed out, the exception is triggered when the
If
The catch-all handler,
Previous Next Top
- Mel Read Attributes
- Mel Reader Mode
- Mel Read Waits
- Mel Properties On Reads
- Agent Mel Property
- Mel Asynchronous Reads
Mel Read Attributes
Let's consider these two mel read statements:
int c1 = <?>store1;
int c2 = <? priority timeout mode=readonly>store2;
The first statement is a simple mel read statement with no attributes. The second statement is a mel read statement with attributes stated:
Operation | Attributes | Synopsis |
---|---|---|
<?>store |
Mel read operation on the mel variable store |
|
priority =n |
Access the mel for reading with priority n | |
timeout =msec |
Wait for the mel to have a value for reading for msec milliseconds before aborting | |
mode =setting |
Request read access to the mel with this mode setting:
reader : request a read access (default)
async : request an asynchronous read access
readonly : request read-only access
|
|
method =setting |
Method used for mel combined reads: mel OR reads and mel AND reads, to be explored in the next chapter. | |
as =var |
Set up var as the stand-in mel variable for the mel read operation. It is mostly used in combination mel reads and mel reader zones. |
Reader Mode
A mel read statement is not only about accessing the remote mel element, but also about waiting for the task's turn to access in one of the mel reader's queues, and then waiting again for the mel element to have a filled slot, and finally removing the read item from the mel buffer. The last action prevents the read value to be read again by another task. These are the mel read conditions to be formalized later.
Asynchronous Mode
Using the asynchronous mode, the task can continue doing other things while the mel read conditions are being met. When the task finally needs the read value, it can check if a value has been successfully read. We will explore asynchronous reads in a later section.
Readonly Mode
It is possible to read the mel value and leave it back in the mel buffer for other reader tasks by using the
mode
attribute readonly
. We will explore the readonly access in a future chapter.
Mel Reader Mode
A mel read operation accesses a mel variable at the reader's end of the mel buffer. For example to read the mel variable
store
into a local variable c
:
c = <? mode=reader> store;
The mode
keyword can always be omitted:
c = <? reader> store;
Finally, the attribute value reader
can also be omitted:
c = <?> store;
Due to the position of the mel variable at the right-hand side of the assignment (=
) operator, a mel read operation can be identified at compile time without the verbose use of the reader
mel buffer access mode. However, even without the =
operator, the reader
mode can also be omitted because it is the default mel buffer access mode. The following statements are equivalent:
<?> store;
<? reader> store;
<? mode=reader> store;
Mel Read Waits
Let's start with a simple Producer/Consumer example with a focus on the Consumer side to explore the mel read access:
main () {
<mel> int store;
<!> Producer (store);
<!> Consumer (store);
}
void Producer (<mel> int store) {
while ( <?>store = Produce() );
<close>store;
}
void Consumer (<mel> int store) {
while ( 1 ) {
try { Consume(<? timeout>store); }
catch ( store<TIMEDOUT> ) {
printf ("Timeout - try again");
continue;
}
catch ( store<CLOSED> ) {
printf ("Store closed - get out");
break;
}
catch ( store<...> ) {
printf ("Unexpected error [%d] due to [%s]",
store<error>, store<why>);
break;
}
}
}
The Producer
task keeps filling the mel store
until it produces a 0 value. After depositing this 0 value to the mel element, it breaks out of the while
loop, closes the mel store
, and ends itself.
The purpose of the
Consumer
task is to Consume
the items produced by Producer
.
Mel Read Process
This is the behind-the-scene process for the statement
<? timeout>store
- The
Consumer
task starts the mel wait operation by setting the properties of the associatedstore
mel variable, per on read entry setting. Of interest, the <error> property is reset to NERW_ERROR_PENDING.
- The
Consumer
task puts itself into one of many possible readers' queues of the melstore
. The readers' queue theConsumer
selects to stand in line is based on the priority of the mel read operation. Here, no priority attribute is explicit so the default readers' queue is used.
- If there are other reader tasks in the queue, the
Consumer
task moves up the queue as the front tasks get off the queue, until it reaches the top position of the queue.
- At the top position, the
Consumer
waits for the queue to have READ access to the melstore
, based on the priority of the queue. All tasks in higher priority queues must be served before any tasks in a lower priority queue.
In this example, sinceConsumer
is the only reader task, there is no vying for the access from higher-priority queues. Therefore, although the default readers' queue has the lowest priority to access the mel buffer, it is immediately granted READ access.
- If there is a product in the
store
mel buffer (i.e. the melstore
is filled),Consumer
checks the staleness of this product through its mel sequence number. Here this check is procedural only since staleness occurs with readonly access, which is not the case here.
- If by some unexpected synchronization issue, the product does not pass the staleness test, the
Consumer
allows a task behind it to "jump the line" to check and retrieve this product item. (If the second task also finds the product stale, CHAOS keeps working down the waiting queue for an accommodating task.)
A task that stands due to product staleness still keeps its position in the queue to wait for a non-stale product to arrive.
- Once
Consumer
has found a fresh product, it removes that product from the mel buffer, and initializes the <value> property of the associated mel variable with the value of that product. It resets the <error> property to NERW_ERROR_NONE, and sets the other properties of the mel variable per on read success setting. The task then gets off the mel read operation, and resumes the processing flow. Here itConsume
s the retrieved product.
The mel buffer now has a vacant slot for theProducer
to deposit a new product.
- If there is no product in the
store
mel buffer (i.e. the melstore
is empty),Consumer
keeps the top position in the queue and waits until the melstore
becomes filled. Then it processes as above.
- If
Consumer
cannot retrieve a product before the timeout, theTIMEDOUT
exception is raised. TheConsumer
task sets the properties of the associatedstore
mel variable per on read failure setting, especially setting the <error> property to NERW_ERROR_TIMEDOUT, gets off the mel wait operation, and processes theTIMEDOUT
catch
handler. Here, it just prints a statement, and then usescontinue
to iterate thewhile
loop.Side note: An alternative to
continue
is <resume>. The continuation process loops back to thewhile
loop and then issues a new mel read statement. On the other hand, the resumption process restarts the wait of the latest mel wait statement, skipping thewhile
loop iteration. Which process to use depends on the logic of the program. In this example here, the resumption would be more efficient.
Note that both methods will putConsumer
back at the bottom of the in-use readers' queue. This allows waiting tasks already in the queue to move to the top. In the example here, sinceConsumer
is the only reading task in our example, it will be back at the top of the readers' queue immediately. - When
Consumer
is waiting for a value, and a 0-valued product arrives,Consumer
will retrieve it andConsume
s it like any other products. On the next iteration of thewhile
loop, there will be no more products from theProducer
. TheConsumer
waits at the mel queue until it receives theCLOSED
exception due to theProducer
having closed the melstore
.
- When the
Consumer
receives theCLOSED
exception, it sets the properties of the associatedstore
mel variable per on read failure setting, especially setting the <error> property to NERW_ERROR_CLOSED, gets off the mel wait operation, and jumps into theCLOSED
catch
handler. In this example, the handlerbreak
s out of thewhile
loop, and with nothing else to do, theConsumer
task ends itself.
store
, the Consumer
detects an exception other than TIMEDOUT
or CLOSED
, it will get off the mel wait operation, and jumps into the catch-all handler:
catch ( store<...> )
Here, it prints the Unexpected error
statement with the error code and cause of the error, and then breaks off the while
loop. Without the catch-all handler for store
, any unexpected exception from store
will cause the Consumer
task to abort abruptly, instead of ending graciously.
Mel Read Conditions
As a summary, the following conditions must be met before a task can read out a mel value:
- The mel element is open and accepts read requests
- The task successfully joins a readers' queue of the mel
- The task has moved up to the top position of the readers' queue
- The readers' queue has been granted READ access to the mel element
- The mel element is filled, with a value in its mel buffer
- The value to be read is not stale for the task
The second condition concerns the
priority
attribute in the mel read statement. Each priority is associated with a separate readers' queue. Without the priority
attribute, the default readers' queue is used. The selected queue must have enough queuing resources to take in the task.
The third condition is relevant when there are other tasks already in the readers' queue. All tasks join a readers' queue at the bottom, and moves up the queue. Only the task at the top of a readers' queue can retrieve the mel value.
The fourth condition is relevant when there are multiple readers' queues vying for access to the same mel element. A queue with a higher priority is granted access to the mel element before lower priority queues.
The fifth condition checks if the mel element is empty. The reader task must wait for a writer task to deposit a value to the mel buffer before it can read it.
The sixth condition is relevant when the reader task finds a value already in the mel element but this value is already read due to a previous read access. This happens when we repeatedly do a readonly access to a mel, and since a readonly access does not remove the mel value, subsequent readonly accesses may see a stale value. Staleness should not happen for normal reads due to the removal of the mel value. However the staleness check is included as part of the read conditions as an additional step to insure integrity, especially in heterogeneous system where different parts running at different speed and reliability, could introduce unexpected inconsistencies. When staleness is discovered, the task must wait first for another reader task to read out that stale value, and then for a writer task to deposit a fresh value to the mel buffer.
Mel Properties On Reads
Mel properties belong to mel variables. A mel variable represents a session between a task and the mel element due to a mel operation. Unlike the remote mel, the mel variable is resident to the task. For the mel read operation, properties are set on entry, and on success or failure.
On Read Entry
This table summarizes the properties settings on entry of a mel read operation:
On Read Entry | ||
---|---|---|
Property | Attribute | Synopsis |
IN Properties | ||
store<priority> |
| The <priority> property is set to the value of the priority attribute. If the attribute is not specified, the property is set to default priority value. CHAOS has the task join the readers' queue corresponding to the requested priority. |
store<timeout> | The <timeout> property is set to the value of the timeout attribute. If the attribute is mentioned, but without a specific value, the timeout value is the system default value. If the attribute is not mentioned, the timeout value is 0, meaning that the read request does not have a timeout timer, and the task is willing to wait until the mel read conditions are satisfied. | |
CORE Properties | ||
The task uses the CORE properties to connect to the remote mel element. The read operation does not modify the CORE properties. | ||
OUT Properties | ||
store<value> | The mel read operation keep the current values of these properties on entry. | |
store<count> | ||
store<sequence> | ||
store<status> | The mel read operation resets these two properties to NERW_STATUS_OPEN on entry. | |
store<condition> | ||
store<error> | The mel read operation resets the <error> property to NERW_ERROR_PENDING on entry. | |
store<why> | The mel read operation resets the <why> property to an empty string on entry. | |
SET Properties | ||
The mel read operation keep the current values of these properties on entry. |
On Read Success
When a mel read operation is successful, the properties of the mel variable are set as follows:
On Read Success | |
---|---|
Property | Synopsis |
IN Properties | |
The IN properties retain the same values as in entry. | |
CORE Properties | |
The read operation does not modify the CORE properties. | |
OUT Properties | |
store<value> | Value read from the remote mel buffer. This value can be a simple entity (like an int ), an array or a structured entity. |
store<count> | Number of items in an array value. This value is null if the value is not an array. |
store<sequence> | Version identifier of the value returned from a mel read operation. This value should be higher than the value of the <sequence> property of the mel variable on entry. |
store<status> | Status of the mel element after the mel read operation. If the mel element has a default buffer of one slot, the <status> is NERW_STATUS_EMPTY if there is no writer task in the waiting. If there is a waiting writer task, the <status> will be NERW_STATUS_FILLED since the mel buffer is expected to be re-filled by that writer task. |
store<condition> | Status of the mel element before the mel read operation. If the <condition> is NERW_STATUS_FILLED , the mel buffer contains at least a value to be read. If the <condition> is NERW_STATUS_EMPTY , the mel buffer does not contain any value or fresh value to be read, and the task had to wait in the mel queue for a value to be deposited by a writer task. |
store<error> | Since this is a successful mel read, the <error> property is set to NERW_ERROR_NONE . |
store<why> | Since this is a successful mel read, the <why> property is an empty string. |
SET Properties | |
Upon a successful mel read, the SET properties are updated with the corresponding values from the remote mel element. |
On Read Failure
When a mel read operation fails, the properties of the mel variable are set as follows:
On Read Failure | |
---|---|
Property | Synopsis |
IN Properties | |
The IN properties retain the same values as in entry. | |
CORE Properties | |
The read operation does not modify the CORE properties. | |
OUT Properties | |
store<value> | These properties retain their values they have on entry of the mel read operation. |
store<count> | |
store<sequence> | |
store<status> | |
store<condition> | |
store<error> | Since this is a failed mel read, the <error> property contains the error code of the failure. |
store<why> | Since this is a failed mel read, the <why> property contains a detailed explanation of the failure. |
SET Properties | |
The SET properties retain the same values as in entry. |
Agent Mel Property
The reader mode that has been discussed so far, is the default mode to read from mel elements. There is another mode which is the mel asynchronous read. Before we explore this mode, let's get introduced to the <agent> mel property.
The <agent> property is one of the IN properties. On entry to any mel operation (including the mel read operation), CHAOS initializes the <agent> property of the local mel variable with a value to indicate the execution entity that will run the mel operation. The <agent> property has the following values:
Value | Synopsis |
---|---|
self |
The mel operation is run under the context of the task itself. This is a direct run where the code flow of the task is suspended until the operation finishes with either success or failure. |
system |
The mel operation is run under the context of the CHAOS runtime system. This is an asynchronous run with the task returning to its code flow immediately after issuing the mel operation request. |
The <agent> property is set up differently depending on the reading mode used:
Setting | Reader Mode | Async Mode | ReadOnly |
---|---|---|---|
On Entry | self | system | self |
On Success | same as on entry | ||
On Failure | same as on entry |
The <agent> property is only changed on entry of a mel operation. Afterwards it reflects the execution agent of the last mel operation.
Mel Asynchronous Reads
With the default reader mode, the task initiates the mel read operation and does the mel wait. We now introduce the asynchronous mode where the task initiates the mel read operation but has the CHAOS runtime does the mel wait for it. The task can use this time to do something else more productive.
Asynchronous Read Basic
Let's start with a
Consumer
task that uses the default reader mode:
void Consumer (<mel> int store) {
Consume (<?> store);
}
The above reader task waits for a writer task to fill the shared mel store
before it can do a read for its own Consume
chore.
Let's now modify
Consumer
to take advantage of the asynchronous reader mode. It will offload the waiting part to CHAOS while it can do some other thing:
void Consumer (<mel> int store) {
<? mode=async> store;
doSomething ();
if ( store<error> == NERW_ERROR_NONE )
Consume (store<value>);
else
Consume (<?> store);
}
The Consumer
task issues the asynchronous read statement:
<? mode=async> store;
to request CHAOS to wait for the mel read conditions on its behalf. Unlike the mel read statement that can suspend the task in a potential mel wait, the asynchronous read statement returns the processing flow to the task immediately after sending the asynchronous read request to CHAOS.
The
Consumer
after doSomething
, is now ready to Consume
a product from the mel store
. It hopes that during the time it is doing doSomething
, CHAOS has been able to successfully finish the mel wait and initialize the properties of the local mel variable store
, per On Read Success settings. In this case, the <error>
property, which was set to NERW_ERROR_PENDING on entry, has been reset to NERW_ERROR_NONE; the <value>
property now contains the newly read value for Consume
; and the rest of the properties adhere to the On Read Success setting.
On the other hand, CHAOS may still be in the mel waiting. The check for NERW_ERROR_NONE in
<error>
thus fails. The Consumer
task could do something else to give CHAOS more time. In the above example, Consumer
does not have anything else to do, so it decides to take over the wait. The mel wait request <?> store
in Consume(<?>store)
, transfers the mel wait responsibility from CHAOS back to the Consumer
task.
In fact, the check for NERW_ERROR_NONE in
<error>
is not necessary. We can simplify code Consumer
as follows:
void Consumer (<mel> int store) {
<? async> store;
doSomething ();
Consume (<?> store);
}
Note that the mode
keyword is now omitted. Like in the mel reader mode, the mode
keyword is optional since the word async can uniquely introduce the asynchronous mode.
The mel read request
<?> store
in Consume(<?>store)
will check if a new value has been read by CHAOS via the asynchronous read request. If it is, the <value> property of the mel variable is immediately returned for Consume
. Otherwise, the Consumer
task will take over the wait.
The above
Consumer
code assumes that there is only success on the mel read, either asynchronously by CHAOS or directly by the task itself. A mel read can also fail. In the next section we will explore how this is handled with asynchronous mel reads.
Asynchronous Read With Error Checking
An asynchronous read operation can be invoked with other mel read attributes. Let's explore the behind-the-scene process of an asynchronous read with timeout and <error> property checking.
void Consumer (<mel> int store) {
<? async timeout> store;
doSomething ();
switch ( store<error> ) {
case NERW_ERROR_NONE:
Consume (store<value>);
break;
case NERW_ERROR_TIMEDOUT:
printf ("CHAOS fails the mel read due to timeout");
Consume ( <?>store );
break;
case NERW_ERROR_CLOSED:
printf ("The async read fails due to closure");
break;
case NERW_ERROR_PENDING:
printf ("Take over the wait with remaining timeout");
Consume (<? timeout=NERW_TIME_REMAIN> store);
break;
default:
printf ("CHAOS has failed the mel wait due to [%d] on [%s]",
store<error>, store<why>);
Consume (<? timeout> store);
break;
}
}
The task Consumer
now invokes the asynchronous mel wait with a timeout and checks the outcome of that wait.
- The
timeout
value in theasync
mel wait statement means that CHAOS has that much time to wait for a read from the melstore
buffer. If it cannot achieve that, it will get off the mel wait and sets the<error>
property to NERW_ERROR_TIMEDOUT, and other properties per On Read Failure.
- CHAOS receives the request, and starts the mel read process on behalf of the
Consumer
task. It sets the <agent> property tosystem
. The other properties are set per On Read Entry.
Consumer
after requesting the asynchronous mel wait, runsdoSomething
, with the hope that once this chore is done, CHAOS has successfully read astore
value.
- With
doSomething
done,Consumer
is now ready to doConsume
. It checks the <error> property of the local mel variablestore
. This property has been updated by CHAOS to mark its progress in its asynchronous mel wait.
- If <error> is NERW_ERROR_NONE, CHAOS has successfully done the mel read, and initializes the <value> property with the read value.
Consumer
thenConsume
s from the <value> property which is a local entity instead of accessing the remote mel element.
- If <error> is NERW_ERROR_TIMEDOUT, CHAOS has aborted the mel wait due to timeout.
Consumer
, after doing aprintf
message, decides to redo the mel wait by itself, this time without the timeout. Since this is a new mel wait, theConsumer
task will join thestore
readers' queue at the bottom end behind existing waiting tasks, if any.
- If <error> is NERW_ERROR_CLOSED, CHAOS has aborted the mel wait due to its detection that the remote mel element has been closed. The
Consumer
task acknowledges this closure with aprintf
, does abreak
from theswitch
statement, and ends itself.
- If <error> remains at NERW_ERROR_PENDING, CHAOS is still waiting to read the mel
store
. TheConsumer
task has a number of options that it can take:
Option Description <?> store
The task takes over the wait from CHAOS. It keeps the current position that CHAOS has attained, in the mel readers' queue. It drops the timeout requirement and is willing to wait indefinitely. <? timeout=NERW_TIME_REMAIN> store
The task takes over the wait from CHAOS. It keeps the current position that CHAOS has attained, in the mel readers' queue. Its wait is restricted to the remaining amount of time left from the original timeout value. <? timeout> store
The task takes over the wait from CHAOS. It keeps the current position that CHAOS has attained, in the mel readers' queue. Its wait is reset to the default timeout value. <? timeout=1000> store
The task takes over the wait from CHAOS. It keeps the current position that CHAOS has attained, in the mel readers' queue. Its wait will time out in 1000 msec. <? priority+1> store
The task takes over the wait from CHAOS. It does not join the mel queue that CHAOS was standing in; instead it joins a higher priority readers' queue, starting at the bottom of that queue. <? priority timeout> store
The task combines both priority and timeout processing as described above when it takes over the mel wait itself. Do nothing The task continues to let CHAOS do the mel waiting in its behalf, and will check back later. The task can use this time to do other worthwhile things.
In this example, theConsumer
task decides to take over the mel wait on the same mel readers' queue, keeping its position gained by CHAOS, and using the remaining timeout.
- If <error> is any other error (
default
case), CHAOS has aborted the mel wait due to that error.Consumer
does aprintf
message for the error code and any cause reported by the underlying platform, then decides to redo the mel wait by itself, this time with a new default timeout. Since this is a new mel read, theConsumer
task will join thestore
readers' queue at the bottom end behind existing waiting tasks, if any.
Asynchronous Read With Exceptions
A drawback with the asynchronous read with error checking is that once the
Consumer
task takes over the mel wait, this wait operation can also fail. Besides error checking code for asynchronous reads, we will need to add another set of error checking code for direct mel reads. Using mel operation exceptions, the <agent> property and the <resume> operation, we can handle error conditions for both the CHAOS asynchronous read and the direct mel read.
void Consumer (<mel> int store) {
try {
<? async timeout> store;
doSomething ();
Consume ( <? timeout=NERW_TIME_REMAIN>store );
}
catch ( store<TIMEDOUT> ) {
if ( store<agent> == "system" ) {
printf ("Retry if CHAOS times out");
<resume timeout=NERW_TIME_NONE>;
}
else if ( store<agent> == "self" ) {
printf ("Give up if Consumer times out");
break;
}
catch ( store<CLOSED> ) {
printf ("The async or direct read fails due to closure");
break;
}
catch ( store<...> ) {
printf ("The mel wait has failed due to [%d] on [%s]",
store<error>, store<why>);
if ( store<agent> == "system" )
<resume>; /* retry with leftover timeout */
break;
}
}
The strategy is similar to the earlier example. The Consumer
task starts out with an asynchronous mel read, and uses the saved time to doSomething
. Once it is ready for the Consume
chore, it issues the standard mel read:
Consume ( <? timeout=NERW_TIME_REMAIN>store );
If at this time the asynchronous mel read has successfully completed, the mel read will return the cached <value> property for the Consume
chore. Otherwise, the Consumer
task will take over the mel wait from CHAOS. With the NERW_TIME_REMAIN setting, it will continue to use the remaining time left from the original asynchronous read.
The asynchronous mel read can fail, due to timeout, mel closure or other causes. If this ever happens, CHAOS will set the <error> and <why> properties of the mel variable, per On Read Failure settings. However CHAOS will not interrupt the
Consumer
task. The latter finishes its doSomething
chore, and when it issues the mel read for the Consume
chore, a pending error will trigger an exception. Note that the exception is triggered because the code is inside a try / catch
construct. Without it, the task still sees the pending error, but need to process it via the error checking method.
The
Consumer
task has three exception handlers: the <TIMEDOUT>, <CLOSED> and catch-all handler. The <CLOSED> handler is common to both the asynchronous and direct mel reads. It just printf
a common message and then allows the Consumer
task to break
out off the handler, and finding no subsequent code to run, the task will end itself.
Things are different with the <TIMEDOUT> handler. If the asynchronous mel read has timed out, the exception is triggered when the
Consumer
task does a mel read for the Consume
chore. In the handler, the task does a printf
acknowledging CHAOS work, and then resumes the last mel wait on the mel store
, which is:
Consume ( <? timeout=NERW_TIME_REMAIN>store );
However, the resumption overwrites the NERW_TIME_REMAIN timeout attribute with a NERW_TIME_NONE value. This is to request a new mel read without timeout. In other words, the Consumer
task, after taking over the mel read from CHAOS, is willing to wait as long as needs be for the mel read conditions to be realized. This kind of wait will not trigger a timeout.
If
Consumer
is willing to wait without timeout, why is there a check for <agent> to be self
in the TIMEDOUT exception handler? This is due to the <resume> request in the catch-all handler.
The catch-all handler,
catch ( store<...> )
, displays the error code and the cause of failure for both the asynchronous mel read and subsequent direct mel reads. For a failure due to the asynchronous mel read, the Consumer
task opts to resume the last mel read, which is the takeover of the mel wait by Consumer
. The <resume> operation this time does not include a timeout attribute; therefore the direct mel wait will use the NERW_TIME_REMAIN value of the takeover mel read statement. If this direct mel wait times out, it will be handled by the TIMEDOUT handler inside the
else if ( store<agent> == "self" )
code block. Here, the Consumer
just gives up on getting a store
value for the Consume
chore.
Previous Next Top
No comments:
Post a Comment