micro:bian manual pages (Digital Systems)
This page has a unix-style manual page for each micro:bian system call, and for the type of messages that are passed as argument to send
and receive
.
exit
Name
exit
– terminate current process
Synopsis
void exit(void);
Description
The exit()
function causes the calling process to terminate. The current process is put in a state where it will never be scheduled again, and the scheduler selects another process to run. The exit()
function never returns to the calling process.
Notes
If the main function of a process returns, this is equivalent to calling exit()
just before returning. This is achieved by making the return address of the initial call of the main function point to the exit
function.
start
Name
start
– create a process
Synopsis
int start(char *name, void (*body)(int), int arg, int stacksize); #define STACK 1024
Description
The function start()
must be called only before concurrent execution of the program begins, typically from the main program init()
. It creates a process with a specified name and body, and arranges to pass an specified integer argument to the body when it is activated.
- The string
name
is a descriptive name for the process used only for debugging. The string should be statically allocated (a string constant is acceptable). Nothing bad will happen if several processes have the same name, apart from a possible ambiguity in printed messages. - The function
body(arg)
is the body of the process: it will be invoked with a single integer argument. It is acceptable to use the same function as the bodies of multiple processes, which then run the same code independently of each other; the integer argument assists in allowing such processes to tell themselves apart. - The integer
arg
is the argument passed to the body when it is called. - The integer
stacksize
gives the size in bytes of the stack space that will be allocated to the process. The total space allocated for all processes must fit within the available RAM; the pre-defined constantSTACK
is a useful default until the true stack requirement of each process have been determined.
The function returns the process ID of the newly created process.
send
Name
send
– send a message
Synopsis
void send(int dest, int type, message *msg);
New interface:
void send(int dest, message *msg); void send_msg(int dest, int type); void send_int(int dest, int type, int val); void send_ptr(int dest, int type, void *val);
Description
The function send()
suspends the calling process until the process with id dest
is ready to receive a message from the calling process. The message is then copied from sender to receiver, and both are free to continue. The argument type
is an integer identifiying the kind of message begin sent. The argument msg
may be NULL
, or may point to a message buffer containing data associated with the message. When the message is delivered, the operating system fills in the sender
and type
fields automatically, and copies other message fields from the buffer, if any.
In the new interface, the type
field and any desired data fields should have been filled in the message buffer msg
before calling send
; the msg
parameter must not be NULL
. The alternative forms send_msg
, send_int
and send_ptr
are provided as a convenience for when the message contains just a type
field, or a type
field together with a single integer or pointer field.
receive
Name
receive
– receive a message
Synopsis
void receive(int type, message *msg); #define ANY (-1)
Description
The function receive()
suspends the calling process until another process sends it a message, either with a specified type, or (if the argument type
has the special value ANY
) a message of any type. The argument msg
, if non-null, must point to a buffer that will store the received message; when a sender is available, the message is coped from sender to receiver, and the sender
and type
fields are filled in with the true identity of the sender and the type of message, and other fields are copied across from the sender's message buffer.
Processes waiting to send to a given process are held in a queue, and are admitted on a first come, first served basis according to the type
argument specified in calls to receive
from the process. Interrupt messages of type INTERRUPT
from the fictitious process HARDWARE
jump the queue and are delivered in preference to others.
sendrec
Name
sendrec
– combinedsend
andreceive
Synopsis
void sendrec(int dest, int type, message *msg); #define REPLY 2
New interface:
void sendrec(int dest, message *msg); #define REPLY 2
Description
The call sendrec(dst, type, msg)
is equivalent to the sequence
send(dest, type, msg); receive(REPLY, msg);
but is slightly more efficient, and avoids a potential problem with priority inversion. It is useful where messages are used to implement a form of remote procedure call by making the client send a request message and then wait for a REPLY
. An implementation restriction means that it is forbidden to use a call to sendrec()
to send a REPLY
message, but that is not needed in common usage, where sendrec()
is used to receive a reply.
In the new interface, again sendrec(dst, msg)
is equivalent to the sequence
send(dest, msg); receive(REPLY, msg);
This time, fields of the message, including its type
field, should have been filled in before the call, and the msg
parameter must not be NULL
.
yield
Name
yield
– allow scheduling of other processes
Synopsis
void yield(void);
Description
The function yield()
invokes the scheduler, allowing other processes to run, just as they would if the calling process invoked send()
or receive()
. The calling process joins the back of the queue of processes at its priority level, and will be scheduled again once other ready processes of the same or higher priority have had a chance to run. Calls to yield()
are not generally needed by applications, but the function is used internally by the operating system as part of the start-up mechanism.
connect
Name
connect
– connect to interrupt source
Synopsis
void connect(int irq);
Description
The function connect()
associates the calling process with a source of interrupts, identified by number. The priority of the process is also set to 0, the most urgent priority. Subsequent interrupts will be converted into messages of type INTERRUPT
to the process from the fictitious process HARDWARE
. In the standard implementation of micro:bian, an interrupt is disabled (with disable_irq()
) before sending the message, and must be re-enabled in the driver process if future interrupts are to be sent.
If the process is not ready to receive the INTERRUPT
message when it is due to be sent, one such message can be queued for each process to be sent later. Normally, the interrupt will be disabled at the same time that such a message is queued; but if a second or subsequent interrupt happens before the first message is delivered, then those interrupts are lost.
priority
Name
priority
– set priority of current process
Synopsis
void priority(int prio); #define P_HANDLER 0 #define P_HIGH 1 #define P_LOW 2 #define P_IDLE 3
Description
The function priority()
sets the priority of the calling process to a specified value. The possible priority levels for a process range from 0 to 3, with lower numbers corresponding to more urgency. Priority 0 is automatically associated with processes connected to interrupts, and priority 3 is reserved for the idle process, which puts the processor to sleep when there is nothing to do. Other processes may have a priority of either 1 or 2. When the scheduler is choosing a process to run, processes with numerically lower priority are preferred. Since processes become ready by sending or receiving messages, and the scheduler runs at those times, it is normally true that the running process is one of the most urgent ones that are ready.
message
Name
message
– data type for messages
Synopsis
typedef struct { /* 16 bytes */ unsigned short type; /* Type of message */ short sender; /* PID of sender */ union { /* An integer, a pointer, or four bytes */ int int1; void *ptr1; struct { byte byte1, byte2, byte3, byte4; }; }; union { int int2; void *ptr2; }; /* Another integer or pointer */ union { int int3; void *ptr3; }; /* A third integer or pointer */ } message;
Description
Structures of type message
are the units of information transmitted by calls to send
and receive
. Each message has two fixed fields: type
, a small integer that identifies the type of message, and sender
, which is filled in by the transmission process with the true process id of the sender. In the context of an application, the type
field determines the interpretation of the rest of the message. Note that there is no protection in the type system against inconsistencies of interpretation between the sender and receiver of a message: a value that is sent as an integer could be interpreted by the receiver as a pointer, with disastrous results.
In addition to the fixed fields, there is space for up to three other pieces of information, each of which can be an integer, a pointer, or (in for the first slot) a group of four bytes. Passing a pointer from one process to another raises the possibility that the memory accessed by the pointer may be shared between the sending and receiving processes. Programs must be written so that concurrent access to this memory does not introduce race conditions. The pointer fields of a message are given the universal pointer type void *
, and it is up to sender and receiver to ensure that they are interpreted as pointers to the same kind of object.
Given a message buffer m
, the fields of m
can be referred to as m.type
and m.sender
, and either m.int1
or m.ptr1
or m.byte1
up to m.byte4
, etc. The C idiom being used here, anonymous nested structures and unions, is not described in the classic text by Kernighan and Ritchie, but is an innovation in C'2011. The meaning should be clear: by m.byte1
we mean the byte1
member of the four-byte structure that is one of the alternatives for the first word of payload in the message. Previous versions of C would have made us write m.word1.bytes.byte1
for the same member.