POSIX Compliancy Wrapper for Azure RTOS ThreadX 1.0 POSIX Compliancy Wrapper Overview The POSIX Compliancy Wrapper supports many of the basic POSIX calls, with some limitations, and utilizes ThreadX® primitives underneath. This POSIX compatibility layer should have good performance since it utilizes internal ThreadX primitives and bypasses basic ThreadX error checking. 1.1 POSIX Compliancy Wrapper Source The Wrapper source code is designed for simplicity and is comprised of separate source files for most functions. Including the supplied pthread.h file will import all the necessary POSIX constants and subroutine prototypes. 1.2 POSIX Compliancy Wrapper Documentation This document itself serves as a POSIX Compliancy Wrapper User Guide by providing an overview of the porting process, including various caveats and pitfalls to watch out for. In addition, each covered POSIX call is documented, including information about supported/unsupported options, limitations, deviations, and suggestions on how to work-around any limitations. 2.0 Installation The POSIX Compliancy Wrapper is easily installed by adding the the posix library to your current application build. Make sure your application build references the same header files as the ones the posix library has been built with. The file pthread.h must be included in your application source where POSIX calls are required. Since the POSIX compliancy wrapper does not cover the complete standard, not all prototypes are provided. Most notably is the header file tx_px_time.h. 2.1 Initialization The POSIX Compliancy Wrapper requires that a special initialization function is called prior to accessing any POSIX calls. The function to call and its prototype is: VOID *posix_initialize(VOID * posix_memory); This function is usually called from the application specific ThreadX initialization routine, tx_application_define(). The memory pointer supplied to posix_initialize must be a contiguouis reserved section of memory that has at least the following number of bytes: POSIX_SYSTEM_STACK_SIZE + TX_REGION0_SIZE_IN_BYTES + /* Region0 size */ (WORK_QUEUE_DEPTH * WORK_REQ_SIZE) + /* system queue size */ POSIX_HEAP_SIZE_IN_BYTES These equates are defined in tx_posix.h. The following additional equates define the number of POSIX objects supported by the POSIX Wrapper (default value is shown): SEM_NSEMS_MAX 100 /* simultaneous POSIX semaphores */ SEM_NAME_MAX 10 /* maximum length of name of semaphore */ SEM_VALUE_MAX 100 /* max value of semaphore while initialization */ POSIX_MAX_QUEUES 32 /* maximum number of simultaneous POSIX message queues supported */ PATH_MAX 10 /* maximum length of name of a message queue */ PTHREAD_THREADS_MAX 256 /* define the maximum number of simultaneous POSIX Pthreads supported. */ POSIX_MAX_MUTEX 32 /* define the maximum number of simultaneous POSIX mutexes sported. */ The function posix_initialize will return a pointer to the next free available memory location for the application. 3.0 POSIX Calls Once posix_initialize returns, POSIX calls can be made. The Threadx POSIX Compliancy Wrapper supports the following POSIX calls: /***********************************************************************/ /* CALLS RELATED TO POSIX MESSAGE QUEUE */ /***********************************************************************/ INT mq_send(mqd_t mqdes, const char * msg_ptr, ssize_t msg_len,ULONG msg_prio ); ssize_t mq_receive(mqd_t mqdes, VOID *pMsg, ssize_t msgLen, ULONG *pMsgPrio ); INT mq_unlink(const char * mqName); INT mq_close(mqd_t mqdes); mqd_t mq_open(const CHAR * mqName, ULONG oflags,...); /***********************************************************************/ /* CALLS RELATED TO POSIX SEMAPHORE */ /***********************************************************************/ INT sem_close(sem_t * sem); INT sem_getvalue(sem_t * sem,ULONG * sval); sem_t *sem_open(const char * name, ULONG oflag, ...); INT sem_post(sem_t * sem); INT sem_trywait(sem_t * sem); INT sem_unlink(const char * name); INT sem_wait( sem_t * sem ); INT sem_init(sem_t *sem , INT pshared, UINT value); INT sem_destroy(sem_t *sem); /***********************************************************************/ /* CALLS RELATED TO POSIX pthreads */ /***********************************************************************/ INT sched_yield(VOID); INT pthread_create (pthread_t *thread, pthread_attr_t *attr, VOID *(*start_routine)(VOID*),VOID *arg); INT pthread_detach(pthread_t thread); INT pthread_join(pthread_t thread, VOID **value_ptr); INT pthread_equal(pthread_t thread1, pthread_t thread2); VOID pthread_exit(VOID *value_ptr); pthread_t pthread_self(VOID); INT pthread_attr_destroy(pthread_attr_t *attr); INT pthread_attr_getdetachstate( pthread_attr_t *attr,INT *detachstate); INT pthread_attr_setdetachstate(pthread_attr_t *attr,INT detachstate); INT pthread_attr_getinheritsched(pthread_attr_t *attr, INT *inheritsched); INT pthread_attr_setinheritsched(pthread_attr_t *attr, INT inheritsched); INT pthread_attr_getschedparam(pthread_attr_t *attr,struct sched_param *param); INT pthread_attr_setschedparam(pthread_attr_t *attr,struct sched_param *param); INT pthread_attr_getschedpolicy(pthread_attr_t *attr, INT *policy); INT pthread_attr_setschedpolicy(pthread_attr_t *attr, INT policy); INT pthread_attr_init(pthread_attr_t *attr); INT phread_attr_getstackaddr( pthread_attr_t *attr,VOID **stackaddr); INT phread_attr_setstackaddr(pthread_attr_t *attr,VOID **stackaddr); INT pthread_attr_getstacksize( pthread_attr_t *attr, ssize_t *stacksize); INT pthread_attr_setstacksize(pthread_attr_t *attr, ssize_t stacksize); INT phread_attr_getstack( pthread_attr_t *attr,VOID **stackaddr, ssize_t *stacksize); INT phread_attr_setstack( pthread_attr_t *attr,VOID *stackaddr, ssize_t stacksize); INT pthread_mutexattr_gettype(pthread_mutexattr_t *attr, INT *type); INT pthread_mutexattr_settype(pthread_mutexattr_t *attr, INT type); INT pthread_mutexattr_destroy(pthread_mutexattr_t *attr); INT pthread_mutexattr_init(pthread_mutexattr_t *attr); INT pthread_mutex_destroy(pthread_mutex_t *mutex); INT pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr); INT pthread_mutex_lock(pthread_mutex_t *mutex ); INT pthread_mutex_unlock(pthread_mutex_t *mutex ); INT pthread_mutex_trylock(pthread_mutex_t *mutex); INT pthread_mutexattr_getprotocol( pthread_mutexattr_t *attr, INT *protocol); INT pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, INT protocol); INT pthread_mutexattr_getpshared (pthread_mutexattr_t *attr, INT *pshared); INT pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, INT pshared); INT pthread_mutex_timedlock(pthread_mutex_t *mutex, struct timespec *abs_timeout); INT pthread_setcancelstate (INT state, INT *oldstate); INT pthread_setcanceltype (INT type, INT *oldtype); INT pthread_cancel(pthread_t thread); VOID pthread_yield(VOID); VOID pthread_testcancel(VOID); INT pthread_getschedparam(pthread_t thread, INT *policy, struct sched_param *param); INT pthread_setschedparam(pthread_t thread, INT policy, const struct sched_param *param); INT sched_get_priority_max(INT policy) INT sched_get_priority_min(INT policy) INT pthread_once (pthread_once_t * once_control, VOID (*init_routine) (VOID)) INT pthread_kill(ULONG thread_id, int sig) INT pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask) /***********************************************************************/ /* CALLS RELATED TO POSIX CONDITION VARIABLE */ /***********************************************************************/ INT pthread_cond_destroy(pthread_cond_t *cond); INT pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr); INT pthread_cond_broadcast(pthread_cond_t *cond); INT pthread_cond_signal(pthread_cond_t *cond); INT pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, struct timespec *abstime); INT pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); /***********************************************************************/ /* CALLS RELATED TO Timer */ /***********************************************************************/ INT nanosleep(struct timespec *req, struct timespec *rem) INT sleep(ULONG seconds) INT clock_gettime(clockid_t t, struct timespec * tspec) INT clock_settime(clockid_t t, const struct timespec * tspec) INT clock_getres(clockid_t t, struct timespec * tspec) /***********************************************************************/ /* CALLS RELATED TO Signal */ /***********************************************************************/ INT sigwait(const sigset_t *set, int *sig) INT sigaddset(sigset_t *set, int signo) INT sigdelset(sigset_t *set, int signo) INT sigemptyset(sigset_t *set) INT signal(int signo, void (*func)(int)) INT sigfillset(sigset_t *set) 4.0 POSIX Compliancy Wrapper Error Handling There are two "error handling" functions defined in tx_posix.c and used throughout the Wrapper, as follows: posix_error_handler posix_internal_error In general these routines are called when basic usage errors occur. These routines may also be used as a place to catch errors that are not detected if the application source is not checking the return status. The default processing for each of these is a simple spin loop. Most functions can provide an error number. The means by which each function provides its error numbers is specified in its description. Some functions provide the error number in a variable accessed through the symbol posix_errno. While other functions return an error number directly as the function value. Functions return a value of zero to indicate success. If more than one error occurs in processing a function call, any one of the possible errors may be returned, as the order of detection is undefined. Some functions may return [ENOSYS] suggesting that an attempt was made to use a function that is not available in this implementation. Each pthread has its own error number, which can be obtained through a function call: INT posix_get_pthread_errno(pthread_t ptid) This call will return the last generated error code for the pthread having ptid as an ID. 5.1 POSIX Compliancy Wrapper Limitations Due to performance and architecture issues, this POSIX Compliancy Wrapper does not support all the POSIX calls. A summary of the POSIX Compliancy Wrapper limitations is as follows: · Configuration · Initialization · Driver and I/O model might require porting of current drivers. · Multi-processor extensions are not supported · Unsupported calls (please see below) . Calls supported with certain limitations (please see list below) The POSIX Compliancy Wrapper supports a subset of POSIX calls. In addition, there are also certain limitations with respect to some services. Below is the list of such limitations: LIMITATIONS Following calls are implemented with some limitations: 1.) mq_open() LIMITATIONS : a.) The value of mode (mode_t) has no effect in this implementation. b.) If pAttr is NULL, the message queue is created with implementation-defined default message queue attributes. The default message queue attributes selected are : #define MQ_MAXMSG 125 [MQ_MAXMSG 1024 (POSIX value)] #define MQ_MSGSIZE 500 [MQ_MSGSIZE 4096 (POSIX value)] #define MQ_FLAGS 0 This is due to limitation of size of posix_region0_byte_pool (64KB ). 2.) mq_send() LIMITATIONS : a.) In POSIX : If more than one mq_send() is blocked on a queue and space becomes available in that queue, the message with the highest priority will be unblocked. THIS FEATURE IS NOT IMPLEMENTED. b.) If a message is sent (or received) to a queue with out opening the named queue, in such a case mqdes (message queue descriptor) pointer is invalid and may result in erratic behavior. 3.) mq_receive() LIMITATIONS : a.) If a receive (or send) message from queue with out it being opened, erratic behavior may ensue. 4.) ULONG sem_close() LIMITATIONS : a.) This routine does not deallocate any system resources. 5.) POSIX SEMAPHORE LIMITATIONS : a.) If any operation (eg. sem_post, sem_wait, sem_trywait, sem_getvalue ) is done on a semaphore before creating or opening (sem_open()) the named semaphore, erratic behavior may result. 6.) ULONG sem_trywait(sem_t * sem) LIMITATIONS : a.) EDEADLKA :->[ This is a return value when deadlock condition is detected; i.e., two separate processes are waiting for an available resource to be released via a semaphore "held" by the other process.] This is not implemented. b.) EINTR :->[ This is a return value when sem_wait() was interrupted by a signal.] This is not implemented. 7.) Thread Cancelation pthread cancelation cleanup handlers are not supported which means pthread_cleanup_push( ) and pthread_cleanup_pop( ) functions are not implemented. When the pthread_cancel( ) function is called the target thread is canceled with immediate effect. (provided cancelability is enabled for the target pthread) The cancelation processing in the target thread shall run asynchronously with respect to the ailing thread returning from pthread_cancel( ). 8.) Attributes for Condition Variable No attributes are supported for condition variable in this implementation. 9.) pthreads suspended by nanosleep() and sleep() calls can not be awakened by signals, once in the suspension both these calls will complete the suspension period. 10.) pthread_once (pthread_once_t * once_control, VOID (*init_routine) (VOID)) There is no provision if the init_routine contains a cancellation point. 6.0 Demonstration System The file posix_demo.c contains a demonstration system that utilizes POSIX calls. This Demo application will demonstrate some of the basic POSIX calls. This demo application should be used as an example of how to integrate the POSIX Compliancy Wrapper into your application. 7.0 Future POSIX Compliancy Wrapper Phases Please get in touch with us for next phases of this POSIX Compliancy Wrapper.