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:


Late-Binding API

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.

Late-Binding API Data Types


TABLE 1-1 Late-Binding API Data Types

Data Type

Description

teja_channel_t

Channel data type

teja_memory_pool_t

Memory pool data type

teja_mutex_t

Mutex data type

teja_queue_t

Queue data type

teja_thread_t

Thread data type


Late-Binding API Macros


TABLE 1-2 Late-Binding API Macros

Macros

Description

TEJA_INFINITE_WAIT

Used to indicate an infinite timeout in teja_wait().

TEJA_IS_RAW_OS

Defined only on bare hardware systems. Such systems support a subset of the Teja API.

TEJA_NO_EVENT

Used when sending data on a channel to indicate that event logic can be skipped.


Late-Binding API Mutex Functions

teja_mutex_lock

Function

int teja_mutex_lock(teja_mutex_t mutex);

Parameters

mutex - Mutex to lock.

Return Values

int - If successful, this function returns 0. In case of an error, this function returns
-1.

Description

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.

Example


if (teja_mutex_lock (mutex) < 0)  
  {  
    printf ("Error locking mutex\n");  
  }  
else  
  {  
    printf ("Entered critical region\n");  
    /* Wait one second */  
    teja_wait_time (1, 0);  
    printf ("Exiting critical region\n");  
    if (teja_mutex_unlock (mutex) < 0)  
      {  
        printf ("Error unlocking mutex\n");  
      }  
  }

teja_mutex_trylock

Function

int teja_mutex_trylock(teja_mutex_t mutex);

Parameters

mutex - Mutex to lock.

Return Values

int - If successful, this function returns 0. In case of an error, this function returns
-1.

Description

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.

Example


if (teja_mutex_trylock (mutex) < 0)  
  {  
    printf ("Trylock on mutex failed\n");  
  }  
else  
  {  
    printf ("Entered critical region\n");  
    /* Wait one second */  
    teja_wait_time (1, 0);  
    printf ("Exiting critical region\n");  
    if (teja_mutex_unlock (mutex) < 0)  
      {  
        printf ("Error unlocking mutex\n");  
      }  
  }

teja_mutex_unlock

Function

int teja_mutex_unlock(teja_mutex_t mutex);

Parameters

mutex - Mutex to unlock.

Return Values

int - If successful, this function returns 0. In case of an error, this function returns
-1.

Description

Unlocks the given mutex. If the mutex was not locked by the current thread the result is undefined. Avoid such behavior.

Example

See the examples in teja_mutex_lock and teja_mutex_trylock.

Late-Binding API Queue Functions

The first word of the node that is enqueued is permitted to be overwritten by the queue implementation.

teja_queue_enqueue

Function

int teja_queue_enqueue(teja_queue_t queue, void * node);

Parameters

queue - Queue to enqueue to.

node - Pointer to node to enqueue.

Return Values

int - If successful, this function returns 0. In case of an error, this function returns -1.

Description

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.

Example


void * node;  
node = teja_malloc (16);  
if (node)  
  {  
    if (teja_queue_enqueue (queue, node) < 0)  
      {  
        printf ("Error while attempting to enqueue a node");  
      }  
  }

teja_queue_dequeue

Function

void * teja_queue_dequeue(teja_queue_t queue);

Parameters

queue - Queue to dequeue from.

Return Values

void * - NULL if the queue was empty or pointer to the dequeued node otherwise.

Description

Dequeues a pointer to a node from the queue. The first word of the returned node might have been overwritten by the queue implementation.

Example


void * node;  
node = teja_queue_dequeue (queue);  
if (node)  
  {  
    printf ("Dequeued node %x\n", node);  
  }  
else  
  {  
    printf ("Queue was empty\n");  
  }

teja_queue_is_empty

Function

int teja_queue_is_empty(teja_queue_t queue);

Parameters

queue - Queue to test.

Return Values

int - 0 if the queue is not empty, 1 if the queue is empty.

Description

Tests to see if the queue is empty.

Example


if (teja_queue_is_empty (queue))  
  {  
    printf ("Queue is empty\n");  
  }  
else  
  {  
    printf ("Queue is not empty\n");  
  }

teja_queue_get_size

Function

int teja_queue_get_size(teja_queue_t queue);

Parameters

queue - Queue to obtain size for.

Return Values

int - -1 if implementation is not provided for this custom implementation, or the number of elements currently in the queue otherwise.

Description

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.

Example


printf ("Queue size is %d\n", teja_queue_get_size (queue));

Late-Binding API Memory Pool Functions

teja_memory_pool_get_node

Function

void * teja_memory_pool_get_node(teja_memory_pool_t memory-pool);

Parameters

memory-pool - Memory pool to allocate from.

Return Values

void * - NULL if the memory pool is empty or the pointer to the newly allocated node.

Description

Returns a pointer to a newly allocated fixed-sized node from the given memory pool.

Example


void * node;  
node = teja_memory_pool_get_node (pool);  
if (node)  
  {  
    printf ("Got node %x\n", node);  
    if (teja_memory_pool_put_node (pool, node) < 0)  
      {  
        printf ("Error putting back node %x to the pool\n", node);  
      }  
    else  
      {  
        printf ("Node %x was put back to the pool\n", node);  
      }  
  }  
else  
  {  
    printf ("Pool was empty\n");  
  }

teja_memory_pool_put_node

Function

int teja_memory_pool_put_node(teja_memory_pool_t memory-pool, void * node);

Parameters

memory-pool - Memory pool to return the node to.

node - Pointer to node to free.

Return Values

int - If successful, this function returns 0. In case of an error, this function returns -1.

Description

Frees a node back to a memory pool.

Example

See the example in teja_memory_pool_get_node.

teja_memory_pool_get_node_from_index

Function

void * teja_memory_pool_get_node_from_index(teja_memory_pool_t memory-pool, int index);

Parameters

memory-pool - Memory pool from which the node belongs.

index - Index of the node.

Return Values

void * - Pointer to the node specified by index.

Description

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.

Example


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");  
  }

teja_memory_pool_get_index_from_node

Function

int teja_memory_pool_get_index_from_node(teja_memory_pool_t memory-pool, void * node);

Parameters

memory-pool - Memory pool from which the node belongs.

Return Values

node - Pointer to a node for which the index is requested.

int - Index of the given node.

Description

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.

Example

See the example in teja_memory_pool_get_node_from_index.

Late-Binding API Channel Functions

teja_channel_is_connection_open

Function

int teja_channel_is_connection_open(teja_channel_t channel);

Parameters

channel - Channel to test.

Return Values

int - 1 if the connection is open, 0 otherwise (or if the channel is connectionless).

Description

Returns 1 if the connection is open, 0 otherwise (or if the channel is connectionless).

Example

See the example in teja_channel_send.

teja_channel_make_connection

Function

int teja_channel_make_connection(teja_channel_t channel);

Parameters

channel - Channel to operate on.

Return Values

int - 0 if operation was successful, -1 otherwise.

Description

Establishes a connection on the given channel (if the channel requires the connection to be established at runtime).

Example

See the example in teja_channel_send.

teja_channel_break_connection

Function

int teja_channel_break_connection(teja_channel_t channel);

Parameters

channel - Channel to operate on.

Return Values

int - 0 if operation was successful, -1 otherwise.

Description

Breaks an existing connection on the given channel.

Example

See the example in teja_channel_send.

teja_channel_send

Function

int teja_channel_send(teja_channel_t channel, short int event, void * message, int message-size);

Parameters

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).

Return Values

int - Number of bytes sent or -1 in case of error.

Description

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.

Example

This example shows how to send data using a channel.


#define MY_EVENT 7  
if (teja_channel_make_connection(chan) < 0)  
  {  
    printf ("Error while estabilishing connecting to the channel\n");  
  }  
if (teja_channel_is_connection_open(chan))  
  {  
    if (teja_channel_send(chan,7,"hello",5) < 0)  
      {  
        printf ("Error sending data on the channel\n");  
      }  
    if (teja_channel_break_connection(chan) < 0)  
      {  
        printf ("Error while tearing down the connection on the channel\n");  
      }  
  }

See also the example in teja_wait, which shows how to receive data from the channel.

Late-Binding API Interruptible Wait

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.

teja_wait

Function

int teja_wait(int seconds, int nanoseconds, int poll-seconds, int poll-nanoseconds, short int * event, void * buffer, int buffer-size, ...);

Parameters

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.

Return Values

int - -1 if error, 0 if timeout expires, or the number of bytes read from channels and copied into the buffer.

Description

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.

Example

This example shows how to receive data from a channel using teja_wait().


#define BUF_SIZE 16  
#define MY_EVENT 7  
#define MY_OTHER_EVENT 8  
struct A  
{  
  short int x;  
  short int y;  
};  
int ret;  
short int evt;  
char buf[BUF_SIZE];  
ret = teja_wait (TEJA_INFINITE_WAIT, 0, 1, 0, &evt, buf, BUF_SIZE, chan, NULL);  
if (ret > 0)  
  {  
    switch (evt)  
      {  
      case MY_EVENT:  
        printf ("%s\n", buf);  
        break;  
      case MY_OTHER_EVENT:  
        printf ("%d,%d\n", ((struct A *)buf)->x, ((struct A *)buf)->y);  
        break;  
      }  
  }  
else if (ret == 0)  
  {  
    printf ("timeout expired\n");  
  }  
else  
  {  
    printf ("teja_wait encountered an error\n");  
  }

See also the example in teja_channel_send, which shows how to send data.


NPOS API

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.

NPOS API Data Types


TABLE 1-3 NPOS API Data Types

Data Type

Description

int8_t

8-bit integer type

int16_t

16-bit integer type

int32_t

32-bit integer type

int64_t

64-bit integer type

teja_fd_handler_t

fd handler type, used with teja_register_fd(). This data type has the following prototype: int (* handler) (teja_socket_t fd, void * signal-context, short int * event, void * msg, int msg-max-size)

teja_signal_handler_t

Signal handler type, used with teja_register_fd(). This data type has the following prototype: int (* handler) (int sig_code, void * signal-context, short int * event, void * msg, int msg-max-size)

teja_sockaddr_t

Sockaddr type, used with socket API

teja_socket_t

Socket type, used with socket API

teja_socklen_t

Socklen type, used with socket API

teja_thread_function_t

Thread function. Has the following prototype: void * (* function) (void *)

teja_thread_handle_t

Thread handle type

uint8_t

8-bit unsigned integer type

uint16_t

16-bit unsigned integer type

uint32_t

32-bit unsigned integer type

uint64_t

64-bit unsigned integer type



TABLE 1-4 NPOS API Macros

Macros

Description

TEJA_AF_INET

 

TEJA_DEFAULT_STACK_SIZE

 

TEJA_FD_SETSIZE

Defined only on bare hardware targets.

TEJA_IS_RAW_OS

 

TEJA_INADDR_ANY

 

TEJA_SOCK_DGRAM

 

TEJA_SOCK_STREAM

 


NPOS API Memory Management Functions

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.

teja_free

Function

void teja_free(void * ptr);

Parameters

ptr - Pointer to buffer to free.

Return Values

void

Description

Frees memory buffer. On bare hardware targets this operation is empty.

teja_malloc

Function

void * teja_malloc(size_t size);

Parameters

size - Size in bytes of memory to allocate.

Return Values

void * - Value to be used as pointer to allocated buffer.

Description

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.

teja_realloc

Function

void * teja_realloc(void * ptr, size_t size);

Parameters

ptr - Pointer to memory to reallocate.

size - Size in bytes of memory to allocate.

Return Values

void * - Pointer to newly allocated memory or NULL if the operation failed. In case of failure the original block is left untouched.

Description

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.

NPOS API Thread Functions

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:


TABLE 1-5 NPOS API Thread Types

Data Type

Description

teja_thread_t

This type is associated only to threads that are defined in the software architecture, and not to dynamic threads, created with teja_thread_handle_start(). This data type is an identifier type.

teja_thread_handle_t

This type is a handle that is associated to every thread in the system, both software architecture threads and dynamic threads. This data type is a handle data structure.


teja_get_thread_id

Function

teja_thread_t teja_get_thread_id(void);

Return Values

teja_thread_t - Thread ID of the current thread.

Description

Returns the thread ID of the current thread. The thread ID can be compared against thread identifiers defined in the software architecture.

teja_get_thread_name_for_id

Function

char * teja_get_thread_name_for_id(teja_thread_t thread-id);

Parameters

thread-id - ID of the thread to operate on.

Return Values

char * - Name of the given thread.

Description

Returns the name of the given thread.

teja_get_id_for_thread_name

Function

teja_thread_t teja_get_id_for_thread_name(char * name);

Parameters

name - Name of the thread to operate on.

Return Values

teja_thread_t - ID of the given thread.

Description

Returns the ID of the given thread.

teja_thread_handle_start

Function

int teja_thread_handle_start(teja_thread_handle_t * thread, teja_thread_function_t function, void * arg, int stack-size, int priority);

Parameters

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.

Return Values

int - 0 if execution was successful, -1 if an error occurred.

Description

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.

teja_thread_handle_end

Function

void teja_thread_handle_end(void);

Return Values

void

Description

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_get_for_thread_id

Function

teja_thread_handle_t * teja_thread_handle_get_for_thread_id(int thread-id);

Parameters

thread-id - ID of the thread to operate on.

Return Values

teja_thread_handle_t * - Handle pointer for the given thread ID.

Description

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.

NPOS API Miscellaneous Functions

teja_thread_shutdown

Function

void teja_thread_shutdown(void);

Return Values

void

Description

Shuts down the current Teja thread.

NPOS API Communication Functions

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:

Signal Handling

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:

File Descriptors

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.

teja_fd_isset

Function

int teja_fd_isset(teja_socket_t socket, teja_fd_set_t * fd-set);

Parameters

socket - File descriptor to check.

fd-set - File descriptor set to operate on.

Return Values

int - Nonzero value if the bit for socket is set in fd-set or 0 otherwise.

Description

This function is available only on OS-based targets or targets for which the TEJA_IS_RAW_OS constant is not defined.

teja_fd_set

Function

void teja_fd_set(teja_socket_t socket, teja_fd_set_t * fd-set);

Parameters

socket - File descriptor to set.

fd-set - File descriptor set to operate on.

Return Values

void

Description

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.

teja_fd_zero

Function

void teja_fd_zero(teja_fd_set_t * fd-set);

Parameters

fd-set - File descriptor set.

Return Values

void

Description

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.

teja_register_fd_handler

Function

int teja_register_fd_handler(teja_socket_t fd, teja_fd_handler_t handler);

Parameters

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.

Return Values

int - 0 if registration was successful, -1 if registration failed.

Description

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.

teja_register_fd_handler_with_context

Function

int teja_register_fd_handler_with_context(teja_socket_t fd, void * fd-context, teja_fd_handler_t handler);

Parameters

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.

Return Values

int - 0 if registration was successful, -1 if registration failed.

Description

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.

teja_thread_handle_send_signal

Function

int teja_thread_handle_send_signal(teja_thread_handle_t * destination-thread-id, int signal-code);

Parameters

destination-thread-id - Destination thread.

signal-code - Signal to send.

Return Values

int - 0 if execution was successful, -1 if an error occurred.

Description

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.

teja_register_signal_handler

Function

int teja_register_signal_handler(int signal-code, teja_signal_handler_t handler);

Parameters

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.

Return Values

int - 0 if registration was successful, -1 if registration failed.

Description

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.

teja_register_signal_handler_with_context

Function

int teja_register_signal_handler_with_context(int signal-code, void * context, teja_signal_handler_t handler);

Parameters

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.

Return Values

int - 0 if registration was successful, -1 if registration failed.

Description

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.

teja_close_pipe

Function

void teja_close_pipe(teja_socket_t socket[2]);

Parameters

socket[2] - Array of teja_socket_t descriptor for the pipe to close.

Return Values

void

Description

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.

teja_open_pipe

Function

int teja_open_pipe(teja_socket_t socket[2]);

Parameters

socket[2]

Return Values

int - 0 if execution was successful. The value is the file descriptor of the opened socket. -1 if an error occurred.

Description

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.

teja_read_from_pipe

Function

int teja_read_from_pipe(teja_socket_t socket, char * buffer, int buffer-size);

Parameters

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.

Return Values

int - if execution was successful the number of read bytes is returned (0 indicates end of file). -1 if an error occurred.

Description

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.

teja_write_to_pipe

Function

int teja_write_to_pipe(teja_socket_t socket, char * buffer, int buffer-size);

Parameters

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.

Return Values

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.

Description

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.

teja_select

Function

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);

Parameters

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).

Return Values

int - Number of descriptor that changed status, 0 if the timeout expired, or -1 in case of error.

Description

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_accept

Function

teja_socket_t teja_accept(teja_socket_t socket, teja_sockaddr_t * address, teja_socklen_t * length);

Parameters

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.

Return Values

teja_socket_t - New connected socket or -1 in case of error.

Description

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_bind

Function

teja_socket_t teja_bind(teja_socket_t socket, teja_sockaddr_t * address, teja_socklen_t * length);

Parameters

socket - Socket to bind.

address - Address to assign to the socket.

length - Length of the address.

Return Values

teja_socket_t - 0 if successful, -1 on error.

Description

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.

teja_close_socket

Function

void teja_close_socket(teja_socket_t socket);

Parameters

socket - Socket to close.

Return Values

void

Description

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.

teja_connect

Function

int teja_connect(teja_socket_t socket, teja_sockaddr_t * address, teja_socklen_t * length);

Parameters

socket - Socket to connect from.

address - Address to connect to.

length - Length of the address.

Return Values

int - 0 on success, -1 on error.

Description

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.

teja_get_ip_address_by_name_or_address

Function

int teja_get_ip_address_by_name_or_address (char * name, int * addr);

Parameters

name - Name to resolve.

addr - Returned address.

Return Values

int - 0 on success, -1 on error.

Description

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.

teja_get_host_name

Function

int teja_get_host_name (char * name, int len);

Parameters

name - User-provided buffer in which the result is stored.

len - Length of the user-provided buffer.

Return Values

int - 0 on success, -1 on error.

Description

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.

teja_htonl

Function

uint32_t teja_htonl(uint32_t host-val);

Parameters

host-val - Unsigned 32-bit value in host format.

Return Values

uint32_t - Unsigned 32-bit value converted to network format.

Description

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.

teja_htons

Function

uint16_t teja_htons(uint16_t host-val);

Parameters

host-val - Unsigned 16-bit value in host format.

Return Values

uint16_t - Unsigned 16-bit value converted to network format.

Description

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.

teja_is_data_available_on_socket

Function

int teja_is_data_available_on_socket(teja_socket_t socket);

Parameters

socket - Socket to check.

Return Values

int - 1 if data is available, 0 otherwise.

Description

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.

teja_listen

Function

int teja_listen(teja_socket_t socket, int backlog);

Parameters

socket - Socket that has previously been opened with teja_open_socket().

backlog - Maximum number of entries in the pending connection queue.

Return Values

int - 0 on success, -1 on error.

Description

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_open_socket

Function

teja_socket_t teja_open_socket(int type);

Parameters

type - Defines the type of socket to open. Can be one of:

Return Values

teja_socket_t - Socket descriptor on success or -1 on error.

Description

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.

teja_read_from_socket

Function

int teja_read_from_socket(teja_socket_t socket, void * buffer, int length, int flags);

Parameters

socket - Socket to read from.

buffer - Buffer into which read data is copied.

length - Length of the buffer.

flags - System-dependent flags.

Return Values

int - Number of bytes received or -1 in case of error.

Description

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.

teja_write_to_socket

Function

int teja_write_to_socket(teja_socket_t socket, void * buffer, int length, int flags);

Parameters

socket - Socket to write to.

buffer - Buffer to write to the socket.

length - Length of the buffer.

flags - System-dependent flags.

Return Values

Number of bytes sent or -1 in case of error.

Description

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.

NPOS API Time Functions

teja_get_time

Function

int teja_get_time(int * seconds, int * nanoseconds);

Parameters

seconds - User-provided variable that contains the current seconds after the call.

nanoseconds - User-provided variable that contains the current nanoseconds after the call.

Return Values

int - 0 on success, -1 on error.

Description

Returns the current time in seconds and nanoseconds. The precision depends on the granularity of the underlying system clock.

teja_wait_time

Function

int teja_wait_time(int seconds, int nanoseconds);

Parameters

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.

Return Values

int - 0 on success, -1 on error.

Description

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.


Miscellaneous Functions

teja_get_argc

Function

int teja_get_argc(void);

Return Values

int

Description

Returns the number of arguments passed to the program on the command line.

teja_get_argv

Function

char ** teja_get_argv(void);

Return Values

char **

Description

Returns an array of strings containing the arguments passed to the program on the command line.


Finite State Automata API

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.


Finite State Automata API Defines


TABLE 1-6 Finite State Automata API Defines

Macros

Description

TEJA_FSM_SINGLE_CONTEXT

If defined the single-context version of the API is used, otherwise the multi-context version of the API is used.

TEJA_FSM_COMPUTED_GOTO

If defined the computed goto optimized version is used, otherwise the regular function pointer based version is used. Computed goto might perform faster, but is not available on all target compilers.

TEJA_FSM_CONTEXT

Pointer to the current context. In case of single-context implementation, this value never changes. In case of multiple-context implementation, this value is updated by the system.


Finite State Automata API Macros

teja_fsm_declare

Function

#define teja_fsm_declare(name)

Parameters

name - Name of the state machine.

Description

Declares a state machine with the given name. This function must be used in the global scope outside functions.

teja_fsm_begin

Function

#define teja_fsm_begin(name initial-state-name context-scheduler context-iterator)

Parameters

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.

Description

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.

teja_fsm_end

Function

#define teja_fsm_end()

Description

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.

teja_fsm_start

Function

#define teja_fsm_start(name)

Parameters

name - Name of the state machine.

Description

Starts execution of a state machine with the given name. This function must be used inside a function.

teja_fsm_state_declare

Function

#define teja_fsm_state_declare(name)

Parameters

name - Name of the state.

Description

Declares a state with the given name. This function must be used inside a state machine declaration, immediately after teja_fsm_begin.

teja_fsm_state_begin

Function

#define teja_fsm_state_begin(name)

Parameters

name - Name of the state.

Description

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.

teja_fsm_state_end

Function

#define teja_fsm_state_end()

Description

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.

teja_fsm_goto_state

Function

#define teja_fsm_goto_state(name)

Parameters

name - Name of the state to jump to.

Description

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.

FSM Example

CODE EXAMPLE 1-1 implements a simple state machine depicted in FIGURE 1-1.


FIGURE 1-1 Finite State Machine Example


CODE EXAMPLE 1-1 Finite State Machine Code Example
#include <stdio.h>  
#if NUM_CONTEXTS == 1  
#define TEJA_FSM_SINGLE_CONTEXT  
#endif  
#include "fsm/teja_fsm.h"  
typedef struct Context  
{  
  void * state;  
  int count;  
} Context;  
static Context contexts[NUM_CONTEXTS];  
#if NUM_CONTEXTS == 1  
#define ctx_scheduler() (&contexts[0])  
#else  
void *  
ctx_scheduler (void)  
{  
  static int i = -1;  
  i = (i + 1) % NUM_CONTEXTS;  
  return &contexts[i];  
}  
#endif  
void *  
ctx_iterator (void)  
{  
  static int i = -1;  
  void * cur_context = 0;  
  i = (i + 1);  
  if (i < NUM_CONTEXTS)  
    cur_context = &contexts[i];  
  else  
    i = -1;  
  return cur_context;  
}  
teja_fsm_declare (my_fsm);  
teja_fsm_begin (my_fsm, s2, ctx_scheduler, ctx_iterator)  
  teja_fsm_state_declare (s1);  
  teja_fsm_state_declare (s2);  
  teja_fsm_state_begin (s1)  
    printf ("t1\n");  
    ((Context *) TEJA_FSM_CONTEXT)->count++;  
    teja_fsm_goto_state (s2);  
  teja_fsm_state_end ()  
  teja_fsm_state_begin (s2)  
    printf ("t2: %d\n", contexts[0].count);  
    if (((Context *) TEJA_FSM_CONTEXT)->count == 100)  
     teja_thread_shutdown();  
    teja_fsm_goto_state (s1);  
  teja_fsm_state_end()  
teja_fsm_end()  
void  
fsm_main (void)  
{  
  int i;  
  for (i = 0; i < NUM_CONTEXTS; i++)  
    {  
      contexts[i].count = 0;  
    }  
  teja_fsm_start (my_fsm);  
}  


C Library Support on Bare Hardware

Teja programs running on bare hardware CMT can use the following standard C library functions: