#include "BBC/LLI.h"
#include "BBC/TASK.h"
Data Structures | |
| struct | _FORK_msg_hdr |
| All messages queued by the FORK routines must be prefaced by this controlling structure. More... | |
| struct | _FORK_msg_sys |
| A predefined message consisting of a FORK_msg_hdr and a single 32-bit location to hold the contents. More... | |
Typedefs | |
| typedef _FORK_fcb | FORK_fcb |
| Typedef for struct _FORK_fcb. | |
| typedef _FORK_msg_hdr | FORK_msg_hdr |
| Typedef for struct _FORK_msg_hdr. | |
| typedef _FORK_msg_sys | FORK_msg_sys |
| Typedef for struct _FORK_msg_sys. | |
| typedef enum _FORK_type | FORK_type |
| Typedef for the enum _FORK_type. More... | |
| typedef enum _FORK_cb_status | FORK_cb_status |
| Typedef for enum _FORK_cb_status. | |
| typedef void * | FORK_cb_prm |
| Typedef for the FORK callback parameter. More... | |
| typedef FORK_cb_status(* | FORK_cb_rtn )(FORK_cb_prm context, struct _FORK_msg_hdr *msg_hdr) |
| Signature of the FORK callback handler. More... | |
Enumerations | |
| enum | _FORK_type { FORK_K_TYPE_NON_BLOCKING = LLI_K_TYPE_NON_BLOCKING, FORK_K_TYPE_FIFO_BLOCKING = LLI_K_TYPE_FIFO_BLOCKING, FOKR_K_TYPE_PRIORITY_BLOCKING = LLI_K_TYPE_PRIORITY_BLOCKING } |
| Enumerates the different blocking types. This determines the behaviour one attempts to remove an system message from an empty list. More... | |
| enum | _FORK_cb_status { FORK_C_DESTROY = -2, FORK_C_ABORT = -1, FORK_C_CONTINUE = 0 } |
| Enumerates the status of the call back routine. More... | |
Functions | |
| int | FORK_fcb_sizeof (void) |
| Returns the size, in bytes, of a FORK Control Block. More... | |
| int | FORK_create (FORK_fcb *fcb, FORK_cb_rtn def_handler, FORK_cb_prm ctx, FORK_cb_prm tmo_ctx, int tmo, FORK_msg_sys *msg_blks, int msg_cnt, FORK_type type, const TASK_attr *attr) |
| Creates a FORK message que. More... | |
| int | FORK_destroy (FORK_fcb *fcb) |
| Destroys a FORK que. More... | |
| int | FORK_qsys (FORK_fcb *fcb, FORK_cb_rtn handler, void *contents, int tmo) |
| Ques a message using the internal FORK message blocks. More... | |
| int | FORK_qusr (FORK_fcb *fcb, FORK_cb_rtn handler, FORK_msg_hdr *msg_hdr) |
| Ques a user composed message. More... | |
The FORK routines provide a convenient way to spread work across to tasks or threads. A interlocked message que is created between the task calling task of FORK_create () and a task/thread created by the FORK_create(). Messages can be placed on this que by any task that has access to the que through the Fork Control Block. In this sense, it is a multi-writer, single-reader half-duplex communication link.
These routines serve much the same purpose as the VxWorks semQ routines with some important advantages.
1. These routines allow one complete control over the memory containing the messages.
The VxWorks send routine merely returns a failure status code when one memory exists to buffer a new message. This causes two problems for the programmer. The first is, exactly when does should one try again. The only recourse here, aside from the non-answer of polling until success, is to provide a synchronizing mechanism. One could give a semaphore when a message was consumed. This seems kludgy, since the semaphore is not tied explicitly to the message que and overly complicated to use. T
The second problem is what does the user do when blocking is not an option, as in an interrupt service routine. The FORK routines allow the user to pre-allocate the message buffer before committing to servicing an interrupt. This ensures that the necessary resources are in hand.
2. The burden of creating the receiving task is taken on by the FORK_create() routine.
Since the metaphor of the FORK routines is to transparently fork the execution path, this seems more natural than manually creating an task/thread to handle the messages. In most cases, this is all the create task is going to do, ie pend on a message que and service the incominig messages.
3. The messsage to be queued is not copied twice as it is in the VxWorks routines (once when sending and once when receiving). This is a direct consequence of allowing the user to do his own management of the message buffers.
USAGE
-----
The user first creates the FORK que by calling FORK_create(). FORK_create() allows control overall the parameters of the FORK que, including the attributes of the FORK servicing task. The user also has the option having the FORK routines create an internally managed pool of message buffers.
A queued message always consists of two quantities, a routine to handle the message and the message contents itself. If the internal message pool, referred to here as the system pool, is used, the contents of the message are limited to a single 32 bit number. If the user chooses to que his own messages, the contents can be any size he wishes, his own obligation is to preface the message with a FORK_msg_hdr structure. Messages of varying sizes and types, ie both user and system messages, can be queued to the same FORK que. The deallocation of user messages are the responsibility of the user, while system messages are freed immediately after the dispatch routine finishes its processing.
This latter design choice has only a slight impact on performance, since, in theory, the dispatch routine could release the message memory earlier. However, given the single reader nature of the FORK utilities, only one such buffer can be outstanding at an given time. The truly concerned user can avoid this limitation by using only message buffers that he manages.
EXAMPLE
-------
FORK_fcb *fcb;
int size;
/ * Allocate 10 message blocks for the FORK ques internal pool * /
FORK_msg_sys msg_blks[10];
int msg_blk_cnt = sizeof (msg_blks) / sizeof (*msg_blks);
size = FORK_fcb_sizeof (); / * Size of Fork Control Block * /
fcb = (FORK_fcb *) malloc (size); / * Allocate the memory for it * /
/ * Create the fork que * /
status = FORK_create (fcb, / * Fork Control Block to init * /
normalPrint, / * Default handling routine * /
forkParameter, / * Parameter passed to handler * /
forkTmoParameter, / * Parameter passed if timeout * /
timeout, / * How long to pend before tmo * /
msg_blks, / * A source of message blocks * /
msg_blk_cnt, / * Number of messge blocks * /
FORK_K_TYPE_FIFO_BLOCKING,
/ * FIFO style blocking when * /
/ * allocating system messges * /
NULL); / * Use default task attributes * /
status = FORK_qsys (fcb, NULL, "Hello World\n", FORK_K_WTO_FOREVER);
status = FORK_qsys (fcb, boldPrint, "Goodbye World\n", FORK_K_WTO_FOREVER);
}
int normalPrint (void *parameter, FORK_msg_sys *msg)
{
fputs (msg->contents);
return FORK_C_CONTINUE;
}
int boldPrint (void *parameter, FORK_msg_sys *msg)
{
printf ("%s", BOLD_ESC_SEQUENCE);
fputs (msg->contents);
printf ("%s", NORMAL_ESC_SEQUENCE);
return FORK_C_CONTINUE;
}
The usual precautions should be heeded. For example, in this example, not allowing the creating task to terminate when messages are still on the que. Since the memory is from stack, that would be bad.
|
|
Typedef for the FORK callback parameter.
This parameter is specified when calling FORK_create() and is passed transparently into the user's callback handler. |
|
|
Signature of the FORK callback handler.
Defines the signature for the user callback & parameter
status = (*cb_rtn) (FORK_cb_prm cb_prm, FORK_msg_hdr *msg_hdr)
Where:
cb_prm: The value of the context parameter passed into the
FORK_create routines.
msg_hdr: A pointer to the message header. This pointer will,
in all likelihood, be recasted into a pointer to
the specific style of message one is expecting.
RETURN VALUE: FORK_C_CONTINUE, keep going.
FORK_C_ABORT, abort the FORK task.
FORK_C_DESTROY, abort the FORK task and destroy the FORK q
|
|
|
Typedef for the enum _FORK_type.
|
|
|
Enumerates the status of the call back routine.
This enumerates the return value of the user's dispatch callback handler. Basically one can tell the FORK pend routine to do one of three things, pend for another message, FORK_C_CONTINUE, abort, FORK_C_ABORT, or FORK_C_DESTROY, abort the FORK que and destroy the FORK que context. Aborting the FORK pend operation kills the FORK servicing task, so be careful that all context has been cleaned up before issuing this return code. It is up to the user to clean-up these resources.
|
|
|
Enumerates the different blocking types. This determines the behaviour one attempts to remove an system message from an empty list.
|
|
||||||||||||||||||||||||||||||||||||||||
|
Creates a FORK message que.
|
|
|
Destroys a FORK que.
|
|
|
Returns the size, in bytes, of a FORK Control Block.
|
|
||||||||||||||||||||
|
Ques a message using the internal FORK message blocks.
Note that because the message is internally allocated it may be possible that this list is exhausted. A timeout parameter is provided to handle this situation. |
|
||||||||||||||||
|
Ques a user composed message.
For the extra work involved in using this routine, the user gets to control his own memory allocation and the exact contents of the message. This means that there is almost no case, other than an internal corruption, under which this routine can fail. |
1.2.13.1 written by Dimitri van Heesch,
© 1997-2001