mirror of
https://github.com/azure-rtos/threadx
synced 2025-02-06 08:08:27 +08:00
363 lines
17 KiB
Plaintext
363 lines
17 KiB
Plaintext
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<64> 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(ALIGN_TYPE 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:
|
||
|
||
<EFBFBD> Configuration
|
||
<EFBFBD> Initialization
|
||
<EFBFBD> Driver and I/O model might require porting of current drivers.
|
||
<EFBFBD> Multi-processor extensions are not supported
|
||
<EFBFBD> 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.
|
||
|
||
|
||
|
||
|