| C H A P T E R 1 |
|
User API |
The user application programming interface (API) consists of functions you can deploy in the application code. This API consists of three main parts:
Additional information is provided in:
The Late-Binding API provides primitives for the synchronization of distributed threads, communication, and memory allocation. This API is treated specially by the tejacc compiler, and is generated dynamically based on contextual information. See the Netra Data Plane Software Suite 1.1 User's Guide for an overview of this API.
int teja_mutex_lock(teja_mutex_t mutex);
int - If successful, this function returns 0. In case of an error, this function returns
-1.
Acquires a mutual exclusion lock. If the mutex is already locked, this function does not return until the mutex becomes available and the lock is acquired for the calling thread. Once the lock is held by the thread, what occurs if this function is called a second time is undefined. If an error is returned, the caller can assume the lock was not acquired.
int teja_mutex_trylock(teja_mutex_t mutex);
int - If successful, this function returns 0. In case of an error, this function returns
-1.
Attempts to lock the given mutex without blocking. If the mutex is already locked, this function exits immediately returning -1, otherwise the function locks the mutex and returns 0. Once the lock is held by the thread, what occurs if this function is called a second time is undefined.
int teja_mutex_unlock(teja_mutex_t mutex);
int - If successful, this function returns 0. In case of an error, this function returns
-1.
Unlocks the given mutex. If the mutex was not locked by the current thread the result is undefined. Avoid such behavior.
See the examples in teja_mutex_lock and teja_mutex_trylock.
The first word of the node that is enqueued is permitted to be overwritten by the queue implementation.
int teja_queue_enqueue(teja_queue_t queue, void * node);
node - Pointer to node to enqueue.
int - If successful, this function returns 0. In case of an error, this function returns -1.
Enqueues a node into a queue. The queue implementation is permitted to overwrite the first word of the node. If -1 is returned, the queue might be full or some other error has occurred.
void * node; node = teja_malloc (16); if (node) { if (teja_queue_enqueue (queue, node) < 0) { printf ("Error while attempting to enqueue a node"); } } |
void * teja_queue_dequeue(teja_queue_t queue);
queue - Queue to dequeue from.
void * - NULL if the queue was empty or pointer to the dequeued node otherwise.
Dequeues a pointer to a node from the queue. The first word of the returned node might have been overwritten by the queue implementation.
void * node; node = teja_queue_dequeue (queue); if (node) { printf ("Dequeued node %x\n", node); } else { printf ("Queue was empty\n"); } |
int teja_queue_is_empty(teja_queue_t queue);
int - 0 if the queue is not empty, 1 if the queue is empty.
Tests to see if the queue is empty.
if (teja_queue_is_empty (queue)) { printf ("Queue is empty\n"); } else { printf ("Queue is not empty\n"); } |
int teja_queue_get_size(teja_queue_t queue);
queue - Queue to obtain size for.
int - -1 if implementation is not provided for this custom implementation, or the number of elements currently in the queue otherwise.
Returns the number of elements in the queue. The function returns a value that is a snapshot in time of the depth of the queue. Not all custom implementations support this function. This function is to be used for debug purposes only, because its implementation (when available) is computationally intensive and not meant for fast path operation.
void * teja_memory_pool_get_node(teja_memory_pool_t memory-pool);
memory-pool - Memory pool to allocate from.
void * - NULL if the memory pool is empty or the pointer to the newly allocated node.
Returns a pointer to a newly allocated fixed-sized node from the given memory pool.
int teja_memory_pool_put_node(teja_memory_pool_t memory-pool, void * node);
memory-pool - Memory pool to return the node to.
node - Pointer to node to free.
int - If successful, this function returns 0. In case of an error, this function returns -1.
Frees a node back to a memory pool.
See the example in teja_memory_pool_get_node.
void * teja_memory_pool_get_node_from_index(teja_memory_pool_t memory-pool, int index);
memory-pool - Memory pool from which the node belongs.
void * - Pointer to the node specified by index.
Memory pool nodes are contiguous in memory and have a sequential index number. This function returns the node that corresponds to the given index. The effect of this function is not equivalent to a teja_memory_pool_get_node call because the node is not actually extracted from the pool. For this reason, the node must be allocated and not free in the memory pool when used by the application. For performance reasons, a range check is not performed, so the index value must be valid or a programming flaw might occur.
void * node; node = teja_memory_pool_get_node_from_index (pool, 3); if (teja_memory_pool_get_index_from_node (pool, node) != 3) { printf ("Impossible!\n"); } |
int teja_memory_pool_get_index_from_node(teja_memory_pool_t memory-pool, void * node);
memory-pool - Memory pool from which the node belongs.
node - Pointer to a node for which the index is requested.
int - Index of the given node.
Memory pool nodes are contiguous in memory and have a sequential index number. This function returns the index that corresponds to the given node pointer. For performance reasons, a range check is not performed, so the node value must be valid or a programming flaw might occur.
See the example in teja_memory_pool_get_node_from_index.
int teja_channel_is_connection_open(teja_channel_t channel);
int - 1 if the connection is open, 0 otherwise (or if the channel is connectionless).
Returns 1 if the connection is open, 0 otherwise (or if the channel is connectionless).
See the example in teja_channel_send.
int teja_channel_make_connection(teja_channel_t channel);
channel - Channel to operate on.
int - 0 if operation was successful, -1 otherwise.
Establishes a connection on the given channel (if the channel requires the connection to be established at runtime).
See the example in teja_channel_send.
int teja_channel_break_connection(teja_channel_t channel);
channel - Channel to operate on.
int - 0 if operation was successful, -1 otherwise.
Breaks an existing connection on the given channel.
See the example in teja_channel_send.
int teja_channel_send(teja_channel_t channel, short int event, void * message, int message-size);
channel - Channel to send data on.
event - Optional value that is sent on the channel with the data. This value can be used at the receiver to discriminate the data type of the received data. This parameter is optional. Passing the constant TEJA_NO_EVENT causes event logic to be skipped in the code generation.
message - Pointer to the data to send.
message-size - Size of the message being sent (in bytes).
int - Number of bytes sent or -1 in case of error.
Sends message-size bytes of data into the channel for the user. This function optionally enables users to send an event value that can be used at the receiver to discriminate the data type of the received data. This functionality is useful if multiple data types are sent. The event logic can be disabled by passing TEJA_NO_EVENT. Depending upon the channel implementation, the user might also be signaled at the time the message is sent.
This example shows how to send data using a channel.
See also the example in teja_wait, which shows how to receive data from the channel.
The teja_wait() call enables users to wait for a timeout to expire or for data to arrive on a list of channels, whichever happens first. This function's semantics are similar to the select() call on UNIX (or Linux) systems. For targets on which the TEJA_IS_RAW_OS constant is not defined, the teja_wait() call can also be interrupted by Teja signals and by registered file descriptors. See NPOS API Communication Functions.
int teja_wait(int seconds, int nanoseconds, int poll-seconds, int poll-nanoseconds, short int * event, void * buffer, int buffer-size, ...);
seconds - Number of seconds to wait. Passing TEJA_INFINITE_WAIT causes the function to wait indefinitely.
nanoseconds - Number of nanoseconds to wait. This value must be from 0 to 999999999.
poll-seconds - Number of seconds to wait before polling channels. Passing TEJA_INFINITE_WAIT causes the function not to poll channels.
poll-nanoseconds - Number of nanoseconds to wait before polling channels. This value must be from 0 to 999999999.
event - Pointer to a variable in which the event value is copied. Passing NULL causes event logic to be skipped.
buffer - Pointer to buffer in which received data is copied.
buffer-size - Size of the buffer.
... - List of channels to read from. The list must be /codeNULL terminated.
int - -1 if error, 0 if timeout expires, or the number of bytes read from channels and copied into the buffer.
Waits for a timeout, for data arriving on one of the channels, or for any registered signals or file descriptor to be triggered, whichever happens first. For more information on signal and file descriptor registration, see NPOS API Communication Functions. Channels are checked once before starting the timeout wait.
The seconds and nanoseconds parameters identify the timeout. If TEJA_INFINITE_WAIT is passed to seconds, then no timing logic is generated and the function waits indefinitely until some data arrives on the channels. The poll-seconds and poll-nanoseconds identify the amount of time to wait between channel polls, while waiting. If TEJA_INFINITE_WAIT is passed to poll-seconds, then no polling logic is generated.
event is an optional parameter. If a non-NULL value is passed the event value coming from the sender is copied in the variable pointed by the event parameter. Typically event is used to discriminate among a set of possible types for the received data so the event can determine what data type to cast the received data to. In case event is not needed (for example, if only one data type is sent on the channel) then the code generator can be instructed to skip event management logic by using TEJA_NO_EVENT at the sender and NULL at the receiver.
Buffer and buffer-size identify the buffer in which received data is copied and its size.
The final variable argument list consists of a NULL-terminated channel list. The order in which channels are listed is the same that is used to poll channels. If no channels are listed, then only timing logic is generated.
This example shows how to receive data from a channel using teja_wait().
See also the example in teja_channel_send, which shows how to send data.
The NPOS API consists of portable abstractions over various operating system facilities such as threads, nonmemory pool-based memory management, thread management, socket communication, and signal registration and handling. Unlike Late-Binding APIs, NPOS APIs are not treated specially by the compiler and are implemented in precompiled libraries. See the Netra Data Plane Software Suite 1.1 User's Guide for an overview of this API.
TEJA_AF_INET |
|
TEJA_DEFAULT_STACK_SIZE |
|
TEJA_FD_SETSIZE |
|
TEJA_IS_RAW_OS |
|
TEJA_INADDR_ANY |
|
TEJA_SOCK_DGRAM |
|
TEJA_SOCK_STREAM |
The memory management functions offer malloc and free functionality. These functions are computationally expensive and only used in initialization code or non-relative critical code. On bare hardware targets the free() function is an empty operation, so use malloc() only to obtain memory that is not meant to be released. For all other purposes, use the memory pool API.
ptr - Pointer to buffer to free.
Frees memory buffer. On bare hardware targets this operation is empty.
void * teja_malloc(size_t size);
size - Size in bytes of memory to allocate.
void * - Value to be used as pointer to allocated buffer.
Allocates memory buffer of specified size. On bare hardware targets the teja_free() operation is empty, so use teja_malloc()only to obtain memory that is not meant to be released. For all other purposes, use the memory pool API.
void * teja_realloc(void * ptr, size_t size);
ptr - Pointer to memory to reallocate.
size - Size in bytes of memory to allocate.
void * - Pointer to newly allocated memory or NULL if the operation failed. In case of failure the original block is left untouched.
Extends the memory buffer to become as big as the specified size. The new block might be allocated at a new address if there was not enough space for size bytes at the original location.
This API offers thread management functionality. The teja_thread_t type implements thread IDs and the type can be assigned thread identifiers defined in the software architecture. You indicate these thread identifiers as strings in the software architecture using teja_thread_create(). In the user application, these identifiers are used as C identifiers (not as strings), which are defined by the compiler.
Two data types can be used to identify threads:
teja_thread_t teja_get_thread_id(void);
teja_thread_t - Thread ID of the current thread.
Returns the thread ID of the current thread. The thread ID can be compared against thread identifiers defined in the software architecture.
char * teja_get_thread_name_for_id(teja_thread_t thread-id);
thread-id - ID of the thread to operate on.
char * - Name of the given thread.
Returns the name of the given thread.
teja_thread_t teja_get_id_for_thread_name(char * name);
name - Name of the thread to operate on.
teja_thread_t - ID of the given thread.
Returns the ID of the given thread.
int teja_thread_handle_start(teja_thread_handle_t * thread, teja_thread_function_t function, void * arg, int stack-size, int priority);
thread - Pointer to an uninitialized TejaThread instance. Upon successful execution, the thread contains a properly set up TejaThread handler.
function - Main function of the thread.
arg - Argument that is passed to the thread main function.
stack-size - Size of the stack for the thread. This functionality is not available on all systems. A predefined value is TEJA_DEFAULT_STACK_SIZE.
priority - prioRity of the thread. This functionality is not available on all systems. A predefined value is TEJA_DEFAULT_PRIORITY.
int - 0 if execution was successful, -1 if an error occurred.
Starts a new thread dynamically, executing the given function. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
void teja_thread_handle_end(void);
Ends a thread that was started with teja_thread_handle_start(). Do not use this function on threads defined in the software architecture. For software architecture threads use teja_thread_shutdown(). This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
teja_thread_handle_t * teja_thread_handle_get_for_thread_id(int thread-id);
thread-id - ID of the thread to operate on.
teja_thread_handle_t * - Handle pointer for the given thread ID.
Returns the thread handle pointer for the given thread ID. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
void teja_thread_shutdown(void);
Shuts down the current Teja thread.
The communication API is only available on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined. This API offers the following functionality:
The Signal Handling API provides cross-platform, efficient signal handling.
The API operates on the teja_thread_handle_t type and can be applied both to software architecture threads and to dynamic threads created with teja_thread_handle_start().
Teja signals can be registered and associated to handler functions. The signals can be sent to a destination teja_thread_handle_t that runs in the same process as the sender. Teja signals are cross-platform and can be used on systems that do not support a UNIX like signaling mechanism (such as Windows). The signals are also more efficient than OS signals and, unlike OS signals, the associated handler is called synchronously.
Any positive integer is a valid Teja signal code that can be passed to the registration function. However, if the signal code is also a valid OS code (such as SIGUSR1 on UNIX), the signal is also registered using the native OS mechanism. This functionality means the thread reacts to OS signals as well as to Teja signals.
An important feature of Teja signals is that when received, the associated handler is called synchronously, so any function can be safely called from within the handler. This functionality removes the typical limitations of asynchronous handling. Even if the registered signal is a valid OS signal code, when the application receives an actual OS signal, the handler is still called synchronously. If a Teja process running multiple threads receives an OS signal, every one of its threads receives the signal, but only the threads that registered the process using the Teja API react to the signal.
Since Teja signals are handled synchronously, threads can only receive signals and execute the registered handler when the thread is in an interruptible state. The interruptible state is given by the teja_wait() function.
A typical, user-defined Teja signal handler reads any data from the relevant source, (for example, a memory-mapped device) and returns the signal to the caller. The caller is always teja_wait(). teja_wait() in turn exits and returns the data to user program.
The features of the signal API are:
Registration of file descriptors (files and sockets) has some similarities to registration of signals. This operation registers a file descriptor with the system and associates the file descriptor with a user-defined handler and optionally with a context, which is also a user-defined value, such as a pointer. Whenever data is received on the file descriptor, the system automatically executes the associated handler and passes the handler to the file descriptor.
Just like Teja signal handlers, file descriptor handlers are invoked synchronously, so any function can be safely called from within the handler. This functionality removes the typical limitations of asynchronous handling.
Since file descriptor handlers are called synchronously, threads can only receive file descriptor input and execute the registered handler when the thread is in an interruptible state. The interruptible state is given by the teja_wait() function.
A typical file descriptor handler reads the data from the file descriptor and returns the data to teja_wait(), which in turn returns the data to the user application.
int teja_fd_isset(teja_socket_t socket, teja_fd_set_t * fd-set);
socket - File descriptor to check.
fd-set - File descriptor set to operate on.
int - Nonzero value if the bit for socket is set in fd-set or 0 otherwise.
This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
void teja_fd_set(teja_socket_t socket, teja_fd_set_t * fd-set);
socket - File descriptor to set.
fd-set - File descriptor set to operate on.
Sets the bit for the given file descriptor into the file descriptor set. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
void teja_fd_zero(teja_fd_set_t * fd-set);
Zeroes the file descriptor set. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_register_fd_handler(teja_socket_t fd, teja_fd_handler_t handler);
fd - File descriptor to register.
handler - Pointer to a user-defined function handler that is executed by the application while in teja_wait() whenever data arrives on fd. If the application is not in teja_wait(), the fd data is not lost and is processed as soon as the application enters teja_wait(). The handler's event and msg parameters are return values that can be assigned by the handler. If the handler is NULL then the file descriptor is deregistered.
int - 0 if registration was successful, -1 if registration failed.
Equivalent to teja_register_fd_handler_with_context(), passing NULL as the fd_context. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_register_fd_handler_with_context(teja_socket_t fd, void * fd-context, teja_fd_handler_t handler);
fd - File descriptor to register.
fd-context - User-provided value (typically a pointer) that is passed to the handler when triggered.
handler - Pointer to a user-defined function handler that is executed by the application while in teja_wait() whenever data arrives on fd. If the application is not in teja_wait(), the fd data is not lost and is processed as soon as the application enters teja_wait(). Upon executing the handler, the system passes the user-defined fd-context to the handler and is referenced in the body of the handler. The handler's event and msg parameters are return values that can be assigned by the handler. If the handler is NULL then the file descriptor is deregistered.
int - 0 if registration was successful, -1 if registration failed.
Registers a file descriptor handling routine and does not need to be called again in the file descriptor handler. Teja file descriptor handlers are synchronous, so all functions can be called from within the handler except blocking functions, because the entire thread gets blocked. The handler can read data from the file descriptor using teja_read_from_socket(). To deregister a file descriptor handler, pass the fd to deregister and a NULL handler. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_thread_handle_send_signal(teja_thread_handle_t * destination-thread-id, int signal-code);
destination-thread-id - Destination thread.
int - 0 if execution was successful, -1 if an error occurred.
Ends a Teja software signal to a thread identified by a teja_thread_handle_t pointer. If the destination thread is not a valid teja_thread_handle_t, the results are undefined. The receiving thread must have registered a signal handler for signal-code, using teja_register_signal_handler().
This API element works only among threads in the same process. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_register_signal_handler(int signal-code, teja_signal_handler_t handler);
signal-code - Identifies the code of the signal for which to register a signal handler. Negative numbers are reserved for the system and cannot be used by applications. If running on a UNIX like OS and the value is that of a proper OS signal code (for example, SIGUSR1), the function also registers the given handler function as an OS signal handler, so that the handler function is also invoked in response to OS software signals.
handler - Pointer to a user-defined function handler that is executed by the application while in teja_wait() whenever a signal is received. If the application is not in teja_wait(), the signal is not lost and is processed as soon as the application enters teja_wait(). The handler's event and msg parameters are return values that can be assigned by the handler. If the handler is NULL then the signal is deregistered.
int - 0 if registration was successful, -1 if registration failed.
Equivalent to teja_register_signal_handler_with_context(), passing NULL as the signal-context. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_register_signal_handler_with_context(int signal-code, void * context, teja_signal_handler_t handler);
signal-code - Identifies the code of the signal for which to register a signal handler. Negative numbers are reserved for the system and cannot be used by applications. If running on a UNIX like OS and the value is that of a proper OS signal code (for example, SIGUSR1), the function also registers the given handler function as an OS signal handler, so that the handler function is also invoked in response to OS software signals.
signal-context - User-provided value (typically a pointer) that is passed to the handler when the handler is triggered.
handler - Pointer to a user-defined function handler that is executed by the application while in teja_wait() whenever a signal is received. If the application is not in teja_wait(), the signal is not lost and is processed as soon as the application enters teja_wait(). Upon executing the handler, the system passes the user-defined signal-context, which can therefore be referenced in the body of the handler. The handler's event and msg parameters are return values that can be assigned by the handler. If the handler is NULL then the signal is deregistered.
int - 0 if registration was successful, -1 if registration failed.
Registers a signal-handling routine. The function does not need to be called again in the signal handler. Teja signal handlers are synchronous so all functions can be called from within the handler except blocking functions, because the entire thread gets blocked. The handler can read data using teja_read_from_socket(). If the function is called on a UNIX like OS and is passed a proper OS signal code (for example, SIGUSR1), the function also registers the given handler function as an OS signal handler. The handler function is also invoked in response to OS software signals. For example, on UNIX like systems, signals are generated with the kill() function. In this situation, the handler function is called synchronously.
To deregister a signal handler, you must pass the signal to deregister and a NULL handler. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
void teja_close_pipe(teja_socket_t socket[2]);
socket[2] - Array of teja_socket_t descriptor for the pipe to close.
Closes the given pipe. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_open_pipe(teja_socket_t socket[2]);
int - 0 if execution was successful. The value is the file descriptor of the opened socket. -1 if an error occurred.
Opens a Teja pipe, creates two teja_socket_t descriptors, and stores them in the sock array. The socket[0] descriptor is used for reading and the socket[1] descriptor is used for writing. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_read_from_pipe(teja_socket_t socket, char * buffer, int buffer-size);
socket - Read descriptor of the pipe to read from.
buffer - Buffer in which read data is stored.
buffer-size - Number of bytes to read from the pipe.
int - if execution was successful the number of read bytes is returned (0 indicates end of file). -1 if an error occurred.
Reads data from a Teja pipe. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_write_to_pipe(teja_socket_t socket, char * buffer, int buffer-size);
socket - Write descriptor of the pipe to write to.
buffer - Buffer in which data to write to the pipe is stored.
buffer-size - Number of bytes to write to the pipe.
int - If execution was successful the number of written bytes is returned (this value is never greater than buffer-size). -1 if an error occurred.
Writes data to a Teja pipe. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_select(int nfds, teja_fd_set_t * read-fds, teja_fd_set_t * write-fds, teja_fd_set_t * exception-fds, int seconds, int nanoseconds);
read-fds - Set of file descriptors to check for change in read status.
write-fds - Set of file descriptors to check for change in write status.
exception-fds - Set of file descriptors to check for change in exception status.
seconds - Seconds before the timeout expires.
nanoseconds - Nanoseconds before the timeout expires (must be less than 1000000000).
int - Number of descriptor that changed status, 0 if the timeout expired, or -1 in case of error.
Waits for a group of file descriptors to change status or for the timeout to expire. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
teja_socket_t teja_accept(teja_socket_t socket, teja_sockaddr_t * address, teja_socklen_t * length);
socket - Socket that has been created with teja_open_socket().
address - Pointer to a structure that contains the address of the connecting program.
length - Size of the structure pointed to by the address. This parameter is overwritten with the length of the returned address.
teja_socket_t - New connected socket or -1 in case of error.
Creates a connected socket starting from the socket parameter. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
teja_socket_t teja_bind(teja_socket_t socket, teja_sockaddr_t * address, teja_socklen_t * length);
address - Address to assign to the socket.
length - Length of the address.
teja_socket_t - 0 if successful, -1 on error.
Assigns the address to the socket. The address is length bytes long. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
void teja_close_socket(teja_socket_t socket);
Closes a socket. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_connect(teja_socket_t socket, teja_sockaddr_t * address, teja_socklen_t * length);
socket - Socket to connect from.
address - Address to connect to.
length - Length of the address.
int - 0 on success, -1 on error.
A socket of type TEJA_SOCK_STREAM establishes a connection to the given address. With a socket of type TEJA_SOCK_DGRAM, the address is the default address to which datagrams are sent and received. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_get_ip_address_by_name_or_address (char * name, int * addr);
int - 0 on success, -1 on error.
Performs a name to address resolution and returns the address in the addr variable. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_get_host_name (char * name, int len);
name - User-provided buffer in which the result is stored.
len - Length of the user-provided buffer.
int - 0 on success, -1 on error.
Returns the host name of the system on which the program is running. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
uint32_t teja_htonl(uint32_t host-val);
host-val - Unsigned 32-bit value in host format.
uint32_t - Unsigned 32-bit value converted to network format.
Converts an unsigned long value from host to network format. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
uint16_t teja_htons(uint16_t host-val);
host-val - Unsigned 16-bit value in host format.
uint16_t - Unsigned 16-bit value converted to network format.
Converts an unsigned short value from host to network format. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_is_data_available_on_socket(teja_socket_t socket);
int - 1 if data is available, 0 otherwise.
Checks whether data is available on a socket. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_listen(teja_socket_t socket, int backlog);
socket - Socket that has previously been opened with teja_open_socket().
backlog - Maximum number of entries in the pending connection queue.
int - 0 on success, -1 on error.
Causes the program to listen for incoming connections on the given socket. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined. Variable that contains the r
teja_socket_t teja_open_socket(int type);
type - Defines the type of socket to open. Can be one of:
teja_socket_t - Socket descriptor on success or -1 on error.
Opens a new socket of the given type. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_read_from_socket(teja_socket_t socket, void * buffer, int length, int flags);
buffer - Buffer into which read data is copied.
length - Length of the buffer.
flags - System-dependent flags.
int - Number of bytes received or -1 in case of error.
Reads data from a socket and stores the data in the provided buffer. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_write_to_socket(teja_socket_t socket, void * buffer, int length, int flags);
buffer - Buffer to write to the socket.
length - Length of the buffer.
flags - System-dependent flags.
Number of bytes sent or -1 in case of error.
Writes data to a socket. This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.
int teja_get_time(int * seconds, int * nanoseconds);
seconds - User-provided variable that contains the current seconds after the call.
nanoseconds - User-provided variable that contains the current nanoseconds after the call.
int - 0 on success, -1 on error.
Returns the current time in seconds and nanoseconds. The precision depends on the granularity of the underlying system clock.
int teja_wait_time(int seconds, int nanoseconds);
seconds - Number of seconds to wait. Passing TEJA_INFINITE_WAIT causes the function to wait indefinitely
nanoseconds - Number of nanoseconds to wait. This value must be between 0 and 999999999.
int - 0 on success, -1 on error.
Causes the current thread to sleep the specified time. The actual sleep time varies, depending upon the granularity of the underlying system clock and the system overhead involved in rescheduling the thread.
Returns the number of arguments passed to the program on the command line.
Returns an array of strings containing the arguments passed to the program on the command line.
This macro-based API can be used to implement efficient state machine logic within a Teja application. States are computational elements and transitions are program flow elements that connect states.
These functions are available in different versions:
State machines come with a user-defined context. The first field of the context must be a void * pointer and is reserved for the system. You can freely add other fields.
The multiple-context version of the API invokes a user-provided scheduler to switch in a new context at the end of each transition. This is an efficient way to implement parallel execution on single-threaded systems. For example, while a context waits, the state machine could switch in a new context and continue computation, thus increasing the CPU utilization.
The single-context version of the API uses a simple pointer scheduler and does not perform any switching. This version is useful on architectures that support multithreading in hardware.
You might choose an implementation based on computed gotos, versus function pointers. Computed gotos might perform faster, but not all target compilers support them.
| Note - State machines need to be declared outside of functions. |
#define teja_fsm_declare(name)
name - Name of the state machine.
Declares a state machine with the given name. This function must be used in the global scope outside functions.
#define teja_fsm_begin(name initial-state-name context-scheduler context-iterator)
name - Name of the state machine.
initial-state-name - Name of the initial state.
context-scheduler - If using single-context mode, this is the pointer to the context. If using multi-context mode this is the name of a user-defined function (of signature void * f (void)) returning the next context.
context-iterator - Name of a user-defined function (of signature void * f (void)) that returns a pointer to the next context until there are no more contexts, in which case the function returns NULL. The system uses this function to iterate over the contexts in the beginning in order to initialize them. This function is not used in single-context mode.
Starts the definition of a state machine of the given name. This function must be used after teja_fsm_declare and must be used in the global scope outside functions. No semi-colon (;) is required at the end of this call.
Ends the definition of a state machine. This function must be used after teja_fsm_begin and must be used in the global scope outside functions. No semi-colon (;) is required at the end of this call.
name - Name of the state machine.
Starts execution of a state machine with the given name. This function must be used inside a function.
#define teja_fsm_state_declare(name)
Declares a state with the given name. This function must be used inside a state machine declaration, immediately after teja_fsm_begin.
#define teja_fsm_state_begin(name)
Starts the definition of a state of the given name. This function must be used inside a state machine after all teja_fsm_declare calls. You can add regular C code immediately after this macro up to the teja_fsm_state_end macro. No semi-colon (;) is required at the end of this call.
Ends the definition of a state. This function must be used after teja_fsm_state_begin. You can add regular C code immediately before this macro. No semi-colon (;) is required at the end of this call.
#define teja_fsm_goto_state(name)
name - Name of the state to jump to.
Performs a jump to the given state. This function must be used inside a state definition (that is between teja_fsm_state_begin and teja_fsm_state_end). This macro can be invoked No semi-colon (;) is required at the end of this call.
CODE EXAMPLE 1-1 implements a simple state machine depicted in FIGURE 1-1.
FIGURE 1-1 Finite State Machine Example
Teja programs running on bare hardware CMT can use the following standard C library functions:
Copyright © 2007, Sun Microsystems, Inc. All Rights Reserved.