TI-POSIX User's Guide
Table of Contents
Overview
Select features of POSIX.1 and POSIX.4 are supported. These include thread, mutex, semaphore, read-write lock, barrier, key, message queue, clock, and timer. We provide a functional implementation of these features, but in some cases, not every aspect of the feature is supported.
Contributions to the POSIX implementation come from the compiler, the C run-time library, and the kernel. Integration with these contributors is provided by the TI-POSIX package.
In general terms, the compiler provides base type definitions, the C library provides language specific features, and TI-POSIX adds features which require kernel support. The following kernels are supported:
- TI-RTOS (also known as SYS/BIOS)
- FreeRTOS
This user’s guide provides information on using POSIX with the kernels listed above. For detailed documentation on POSIX, please use the following links:
- The Open Group POSIX Specification (IEEE Std 1003.1-2008)
- POSIX Programming, Lawrence Livermore National Laboratory
Building Your Program with TI-POSIX Support
There are three steps to using the TI-POSIX support in your program:
- Use POSIX in your source code
- Define your include path
- Link your program with TI-POSIX
The details of each step are given in the following sections.
Use POSIX in your source code
Include the POSIX header files in your source code using the file names defined by the Open Group Specification. For example, use the following to create a POSIX thread:
#include <pthread.h>
void *start_fxn(void *arg);
pthread_t thread;
int arg = 1;
pthread_create(&thread, NULL, start_fxn, (void *)&arg);
In previous versions of SYS/BIOS, the POSIX header files were included using a package-qualified path name. This is no longer supported. Do not use the following include statements:
#include <ti/sysbios/posix/pthread.h> INCORRECT
#include <ti/sysbios/posix/sys/types.h> INCORRECT
Use the following include statements:
#include <pthread.h>
#include <sys/types.h>
Define Your Include Path
The include path is used to select which TI-POSIX implementation you use at compile time. The include path must reflect which tool chain is in play. We currently support three vendors. Set your include path according to which compiler you are using.
Compiler Vendor | Tag | Include Path |
---|---|---|
Texas Instruments | ccs | /.../ti/posix/ccs |
Texas Instruments (clang) | ticlang | /.../ti/posix/ticlang |
GNU | gcc | /.../ti/posix/gcc |
IAR Systems | iar | /.../ti/posix/iar |
The compiler’s include directory is always added implicitly as the last entry on the include path. Thus, when an application includes a POSIX header file (e.g. #include <fcntl.h
) which is not provided by TI-POSIX, it will get the one from the compiler. In some cases, the compiler does not provide the header file (e.g. #include <mqueue.h>
) but it is provided by TI-POSIX. When a header file is provided by the compiler but needs additional content (e.g. errno.h
), TI-POSIX will proxy the header file, include the same file from the compiler, and then add the necessary content.
For example, TI ARM compiler provides errno.h
but does not define the ECONNREFUSED error code. When you compile your source code with TI-POSIX on the include path, this error code will be added.
#include <errno.h>
if (errno == ECONNREFUSED) {
/* handle error */
}
When you compile this source file with TI-POSIX on the include path, the file include chain looks like this:
. /.../ti/posix/ccs/errno.h
.. /.../ti_cgt_arm/include/errno.h
After the compiler’s errno.h has been included, the TI-POSIX errno.h
will reflect on the existing definitions, and if an error code is still missing, it will be added.
#ifndef ECONNREFUSED
#define ECONNREFUSED 111
#endif
This approach ensures all code remains compatible with existing error codes while only defining new error codes which are absent.
A similar approach is taken for other POSIX types and functions.
Link your program with TI-POSIX
The TI-POSIX implementation must be compiled and linked into your program. The details depend on which RTOS kernel you are using.
Using TI-POSIX with TI-RTOS
To use TI-POSIX with the TI-RTOS kernel, simply add the following line to your kernel or application configuration script:
xdc.useModule('ti.posix.tirtos.Settings');
This will modify the kernel build such that the TI-POSIX implementation is compiled into the kernel library.
The Settings module is used to configure the behavior of the TI-POSIX implementation on TI-RTOS.
Settings.enableMutexPriority
This is a Boolean parameter that defaults to false. If set to true, the priority inheritance and priority ceiling mutex protocols will be available, which also increases code size. If these mutex protocols are not needed, leave the parameter at its default value.
Example configuration:
var Settings = xdc.useModule('ti.posix.tirtos.Settings');
Settings.enableMutexPriority = true;
Using TI-POSIX with FreeRTOS
We recommend you compile the TI-POSIX implementation along with the FreeRTOS kernel sources into the kernel library. To do this, simply add the following source files to your kernel build. Note that some compilers require additional source files.
ti/posix/freertos/clock.c
ti/posix/freertos/memory.c
ti/posix/freertos/mqueue.c
ti/posix/freertos/pthread_barrier.c
ti/posix/freertos/pthread_cond.c
ti/posix/freertos/pthread.c
ti/posix/freertos/pthread_mutex.c
ti/posix/freertos/pthread_rwlock.c
ti/posix/freertos/sched.c
ti/posix/freertos/semaphore.c
ti/posix/freertos/sleep.c
ti/posix/freertos/timer.c
Texas Instruments Compiler
ti/posix/freertos/PTLS.c
ti/posix/freertos/aeabi_portable.c
IAR Compiler
ti/posix/freertos/Mtx.c
Note that Texas Instruments does not provide a FreeRTOS port for all devices. When a FreeRTOS port is not available for a particular device, you must use TI-POSIX with TI-RTOS.
Binary Compatibility between TI-RTOS and FreeRTOS
When Texas Instruments provides both TI-RTOS and FreeRTOS for a given device, TI-POSIX supports binary compatibility between both kernels. This is useful when you are shipping libraries which use TI-POSIX. Such a library can be linked with either kernel.
To achieve binary compatibility without binding to a kernel, the POSIX object definitions have been constructed using opaque objects. This allows the compiler to allocate the proper space without binding the source code to kernel header files. However, this approach incurs a memory cost as the object size must be large enough to contain the kernel object with the largest footprint, regardless which kernel is in play. Also, the opaque object definitions are sensitive to changes in the kernel objects.
Therefore, be mindful of the kernel versions. Binary compatibility is only supported between the kernel versions which ship in a given SDK. Binary compatibility is not guaranteed when upgrading to a kernel version not shipped in the SDK. Please consult the SDK documentation to see which kernel versions are supported in that SDK release.
System Error Numbers
The compiler provides a definition for the errno
symbol. In a single-thread application, errno
may be a global identifier declared with external linkage. But in a multi-thread application, errno
is typically stored in thread-local storage (TLS). This requires integration with the kernel. Each compiler provides a different implementation.
The TI-POSIX implementation is partitioned by compiler vendor.
CCS and TICLANG Compiler
By default, the compiler provides one global identifier for errno
. However, when _AEABI_PORTABILITY_LEVEL
is defined, errno
becomes a function call to __aeabi_errno_addr()
. The errno.h provided by TI-POSIX defines this symbol before including the compiler errno.h. In addition, TI-POSIX provides an implementation of __aeabi_errno_addr()
which uses TLS. Finally, the TI-POSIX errno.h defines error codes which are omitted from the compiler header file.
/* file: /ti/posix/ccs/errno.h */
#define _AEABI_PORTABILITY_LEVEL 1
/* include compiler header file */
#include <../include/errno.h>
#ifndef EAGAIN
#define EAGAIN 11
#endif
/* ... */
Note: With newer versions of the TI ARM compiler, it is no longer necessary to define
_AEABI_PORTABILITY_LEVEL
in order to get the thread-safe implementation of errno. It is provided by default.
The CCS ARM compiler does not provide any TLS support. Therefore, the implementation of __aeabi_errno_addr()
is dependent on which kernel is in play. However, the CCS C6x compiler does support TLS. With that compiler, the kernel integration makes use of the compiler TLS support functions.
Compiler | Kernel | Implementation | Compiler Support | RTS Stubs |
---|---|---|---|---|
TI-ARM | TI-RTOS | ti.sysbios.rts.ti.ReentSupport | none | __aeabi_errno_addr() |
TI-ARM | FreeRTOS | ti.posix.freertos.PTLS | none | __aeabi_errno_addr() |
TI-C6x | TI-RTOS | ti.sysbios.rts.ti.ThreadLocalStorage | __TI_tls_block_size() __TI_tls_init() |
__c6xabi_get_tp() |
GNU Compiler
The GCC compiler provides all necessary error numbers needed by the TI-POSIX implementation. We simply include the compiler’s header file.
/* file: /ti/posix/gcc/errno.h */
/* include compiler header file */
#include <../include/errno.h>
The GCC run-time support library, provides thread-safe access to the errno
symbol through the use of a re-entrancy structure called struct _reent
. The first element of this structure is used for storing a thread-specific errno value. The reent struct contains additional elements needed for making many of the Standard C library functions re-entrant.
The current reent structure is accessed either through the global pointer _impure_ptr
, or by calling the function __getreent()
. It is the responsibility of the kernel to manage the context of the current reent struct each time a thread switch occurs.
Texas Instruments provides a custom build of the Newlib-nano C run-time library built with re-entrancy support and which requires the kernel to implement the following functions.
Newlib-nano C library function stubs | Comments |
---|---|
__getreent() |
Return the pointer to the current re-entrancy structure |
__libc_lock_init() |
Initialize the system lock |
__libc_lock_init_recursive() |
Initialize the recursive system lock |
__libc_lock_acquire() |
Acquire the system lock |
__libc_lock_acquire_recursive() |
Acquire the recursive system lock |
__libc_lock_release() |
Release the system lock |
__libc_lock_release_recursive() |
Release the recursive system lock |
__libc_lock_try_acquire() |
Attempt to acquire the system lock |
__libc_lock_try_acquire_recursive() |
Attempt to acquire the recursive system lock |
__libc_lock_close() |
Finalize the system lock |
__libc_lock_close_recursive() |
Finalize the recursive system lock |
The implementation of these functions is provided by the following component:
Kernel | Implementation |
---|---|
TI-RTOS | ti.sysbios.rts.gnu.ReentSupport |
When using FreeRTOS, the Newlib-nano C library provided by the GCC compiler is used. The FreeRTOS kernel manages the current reent struct by directly updating the global pointer _impure_ptr
. Each task contains an embedded struct _reent
structure in its TCB object. However, the system locks needed for thread-safety are not implemented.
The implementation of the reent struct in done directly in the FreeRTOS kernel when enabled with the NEWLIB_REENTRANT config macro.
Kernel | Implementation |
---|---|
FreeRTOS | FreeRTOS.h: configUSE_NEWLIB_REENTRANT = 1 task.c |
IAR Compiler
The TI-POSIX errno.h
header file for IAR defines error codes which are omitted from the compiler’s header file.
/* file: /ti/posix/iar/errno.h */
/* include compiler header file */
#include <../inc/c/errno.h>
#ifndef EAGAIN
#define EAGAIN 11
#endif
/* ... */
By default, the compiler provides one global identifier for errno
. This symbol is implemented as a function call to __aeabi_errno_addr()
, which returns the address of the global symbol. However, when linking with the IAR Multi-Thread RTS library (--threaded_lib
), the implementation of this function makes use of Thread-Local Storage (TLS) for errno
.
When using the Multi-Thread RTS library (MTS), there are several functions which have a binding to the kernel. For example, the allocation and management of the TLS block must be handled by the kernel. To facilitate this, the following functions in the MTS library must be implemented by the kernel.
MTS library function stubs | Comments |
---|---|
__aeabi_read_tp() |
Return the pointer to the current TLS |
__iar_system_Mtxinit() |
Initialize the system lock |
__iar_system_Mtxdst() |
Finalize the system lock |
__iar_system_Mtxlock() |
Acquire the system lock |
__iar_system_Mtxunlock() |
Release the system lock |
For a full descriptions of these functions, see the header file DLib_Threads.h
in the compiler include folder.
The implementation of these functions is provided by the following components:
Kernel | Implementation |
---|---|
TI-RTOS | ti.sysbios.rts.iar.MultithreadSupport |
FreeRTOS | ti.posix.freertos.Mtx |
Summary of functions supported in TI-POSIX
The following tables show the calling context for the POSIX functions supported in TI-POSIX. A supported function does not guarantee that all features of the API are available. Names with strike-through marks are not supported.
In the context of an RTOS, there are three execution contexts:
- main - in the function main(), before invoking the RTOS scheduler
- task - in a native RTOS thread (i.e. not from a pthread)
- interrupt - in an interrupt service routine
All supported POSIX functions may be invoked from a pthread.
A few POSIX functions may be invoked from main context or from task context (i.e. a native RTOS thread). These functions are typically used for creating a POSIX thread (i.e. pthread). The tables below indicate the valid calling context.
Although POSIX is a thread level API, a few functions have been implemented to support interrupt execution context. Keep in mind, that code written for interrupt context must always run to completion; do not make any blocking calls. These functions are listed below.
Thread Function Calling Context
Name | Synopsis | Main | Task |
---|---|---|---|
pthread | Thread Management | ||
pthread_cancel | Send a cancellation request to a thread | No | Yes |
pthread_cleanup_pop | Pop thread cancellation clean-up handler | No | Yes |
pthread_cleanup_push | Push thread cancellation clean-up handler | No | No |
pthread_create | Create a new thread | Yes | Yes |
pthread_detach | Detach a thread | No | Yes |
pthread_equal | Compare thread IDs | Yes | Yes |
pthread_exit | Terminate calling thread | No | No |
Not supported | |||
Not supported | |||
pthread_getschedparam | Use to get priority of a pthread | No | Yes |
pthread_getspecific | Get thread-specific data for calling thread | No | No |
pthread_join | Join with a terminated thread | No | Yes |
pthread_key_create | Create a thread-specific data key | No | No |
pthread_key_delete | Delete a thread-specific data key | No | No |
pthread_once | Run an initialization routine once | No | Yes |
pthread_self | Obtain ID of the calling thread | No | No |
pthread_setcancelstate | Set cancel-ability state and type | No | No |
Not supported. Only asynchronous cancellation is supported. | |||
Not supported | |||
pthread_setschedparam | Use to set priority of a thread | No | No |
Not supported. Use pthread_setschedparam to set priority. | |||
pthread_setspecific | Set thread-specific data for calling thread | No | No |
Not supported | |||
pthread_attr | Thread Attributes | ||
pthread_attr_destroy | Destroy thread attributes object | Yes | Yes |
pthread_attr_getdetachstate | Get detach state in attributes object | Yes | Yes |
pthread_attr_getguardsize | Get guard size in attributes object | Yes | Yes |
Not supported - kernel scheduling policy is fixed | |||
pthread_attr_getschedparam | Get scheduling parameters in attributes object | Yes | Yes |
Not supported - kernel scheduling policy is fixed | |||
Not supported - kernel has no notion of process | |||
pthread_attr_getstack | Get stack size and address attributes | Yes | Yes |
pthread_attr_getstacksize | Get stack size in attributes object | Yes | Yes |
pthread_attr_init | Initialize thread attributes object | Yes | Yes |
pthread_attr_setdetachstate | Set detach state in attributes object | Yes | Yes |
pthread_attr_setguardsize | Set guard size in attributes object | Yes | Yes |
Not supported - kernel scheduling policy is fixed | |||
pthread_attr_setschedparam | Set scheduling parameters in attributes object | Yes | Yes |
Not supported - kernel scheduling policy is fixed | |||
Not supported - kernel has no notion of process | |||
pthread_attr_setstack | Set the stack size and address | Yes | Yes |
pthread_attr_setstacksize | Set the stack size | Yes | Yes |
pthread_barrier | Thread Synchronization | ||
pthread_barrier_destroy | Destroy a barrier object | Yes | Yes |
pthread_barrier_init | Initialize a barrier object | Yes | Yes |
pthread_barrier_wait | Synchronize at a barrier | No | Yes |
pthread_barrierattr | Barrier Attributes | ||
pthread_barrierattr_destroy | Destroy the barrier attributes object | Yes | Yes |
pthread_barrierattr_getpshared | Not supported - kernel has no notion of process | ||
pthread_barrierattr_init | Initialize the barrier attributes object | Yes | Yes |
pthread_barrierattr_setpshared | Not supported - kernel has no notion of process | ||
pthread_cond | Condition Variable | ||
pthread_cond_broadcast | Unblock all threads blocked on a condition variable | No | Yes |
pthread_cond_destroy | Free resources allocated for a condition variable | Yes | Yes |
pthread_cond_init | Allocate and initialize a condition variable | Yes | Yes |
pthread_cond_signal | Unblock a thread waiting on a condition variable | No | Yes |
pthread_cond_timedwait | Wait on a condition variable with a timeout | No | Yes |
pthread_cond_wait | Wait on a condition variable | No | Yes |
pthread_condattr | Condition Variable Attributes | ||
pthread_condattr_destroy | Destroy condition variable attributes object | Yes | Yes |
Not supported | |||
Not supported | |||
pthread_condattr_init | Initialize condition variable attributes object | Yes | Yes |
Not supported | |||
Not supported | |||
pthread_mutex | Mutual Exclusion | ||
pthread_mutex_destroy | Free resources allocated for a mutex | Yes | Yes |
pthread_mutex_getprioceiling | Get the priority ceiling of a mutex [1][3] | Yes | Yes |
pthread_mutex_init | Allocate and initialize a mutex | Yes | Yes |
pthread_mutex_lock | Lock a mutex | No | No |
pthread_mutex_setprioceiling | Set the priority ceiling of a mutex [1][2][3] | No | Yes |
pthread_mutex_timedlock | Wait for a mutex with a timeout | No | No |
pthread_mutex_trylock | Lock a mutex if it is available, return without blocking | No | No |
pthread_mutex_unlock | Unlock a mutex owned by the calling thread | No | No |
pthread_mutexattr | Mutex Attributes | ||
pthread_mutexattr_destroy | Destroy a mutex attributes object | Yes | Yes |
pthread_mutexattr_getprioceiling | Get the priority ceiling of the mutex attributes object [3] | Yes | Yes |
pthread_mutexattr_getprotocol | Get to protocol of the mutex attributes object [3] | Yes | Yes |
Not supported | |||
pthread_mutexattr_gettype | Get the mutex type attribute | Yes | Yes |
pthread_mutexattr_init | Initialize a mutex attributes object | Yes | Yes |
pthread_mutexattr_setprioceiling | Set the priority ceiling of the mutex attributes object [3] | Yes | Yes |
pthread_mutexattr_setprotocol | Set the protocol of the mutex attributes object [3] | Yes | Yes |
Not supported | |||
pthread_mutexattr_settype | Set the mutex type attribute | Yes | Yes |
pthread_rwlock | Read-Write Lock | ||
pthread_rwlock_destroy | Destroy a read-write lock object | Yes | Yes |
pthread_rwlock_init | Initialize a read-write lock object | Yes | Yes |
pthread_rwlock_rdlock | Lock a read-write lock object for reading | No | No |
pthread_rwlock_timedrdlock | Lock a read-write lock object for reading with a timeout | No | No |
pthread_rwlock_timedwrlock | Lock a read-write lock for writing with a timeout | No | No |
pthread_rwlock_tryrdlock | Attempt a read-write lock for reading (non-blocking) | No | No |
pthread_rwlock_trywrlock | Attempt a read-write lock for writing (non-blocking) | No | No |
pthread_rwlock_unlock | Unlock a read-write lock object | No | No |
pthread_rwlock_wrlock | Lock a read-write lock object for writing | No | No |
pthread_rwlockattr | Read-Write Lock Attributes | ||
pthread_rwlockattr_destroy | Destroy the read-write lock attributes object | Yes | Yes |
Not supported | |||
pthread_rwlockattr_init | Initialize the read-write lock attributes object | Yes | Yes |
Not supported |
- [1] The mutex must be using protocol PTHREAD_PRIO_PROTECT.
- [2] May change the priority of the calling thread if it owns the mutex.
- [3] Not available with minimal pthread configuration.
Miscellaneous Function Calling Context
Name | Synopsis | Main | Task |
---|---|---|---|
clock | |||
clock_gettime | Get the current time | Yes | Yes |
clock_nanosleep | High resolution sleep with specifiable clock | No | Yes |
clock_settime | Set the current time for the CLOCK_REALTIME clock | Yes | Yes |
message queue | |||
mq_close | Close a message queue | Yes | Yes |
mq_getattr | Get message queue attributes | Yes | Yes |
mq_open | Open a message queue | Yes | Yes |
mq_receive | Receive a message from a message queue | No | Yes |
mq_send | Send a message to a message queue | No | Yes |
mq_setattr | Set message queue attributes | Yes | Yes |
mq_timedreceive | Receive a message from a message queue, with timeout | No | Yes |
mq_timedsend | Send a message to a message queue, with timeout | No | Yes |
mq_unlink | Remove a message queue | Yes | Yes |
semaphore | |||
sem_destroy | Destroy a semaphore | Yes | Yes |
sem_getvalue | Get the semaphore count | Yes | Yes |
sem_init | Initialize a semaphore | Yes | Yes |
sem_post | Unlock a semaphore (i.e. increment the semaphore count) | Yes | Yes |
sem_timedwait | Lock a semaphore, with timeout | No | Yes |
sem_trywait | Attempt to lock semaphore (non-blocking) | No | Yes |
sem_wait | Lock a semaphore | No | Yes |
sleep | |||
nanosleep | High resolution sleep | No | Yes |
timer | |||
timer_create | Create a timer | Yes | Yes |
timer_delete | Delete a timer | Yes | Yes |
timer_gettime | Fetch the amount of time until the timer expires | Yes | Yes |
timer_settime | Set the time until the next expiration of the timer | Yes | Yes |
Interrupt Calling Context
The following functions may be invoked from interrupt context. Note the non-blocking requirement.
Name | Synopsis |
---|---|
sem_post | Unlock a semaphore (i.e. increment the semaphore count) |
mq_getattr | Get message queue attributes |
mq_receive (non-blocking only) | Receive a message from a message queue |
mq_send (non-blocking only) | Send a message to a message queue |
mq_timedreceive (non-blocking only) | Receive a message from a message queue |
mq_timedsend (non-blocking only) | Send a message to a message queue |
Implementation Notes
The following sections provide some notes on the TI-POSIX implementation details.
Thread default stack size and thread default priority
int pthread_attr_init(pthread_attr_t *attr)
pthread_attr_init()
initializes the pthread_attr_t
object pointed to by attr
with default values, which includes the stack size and thread priority.
On TI-RTOS, the default stack size is defined in the configuration script.
var Task = xdc.useModule('ti.sysbios.knl.Task');
Task.defaultStackSize = 0x800;
On FreeRTOS, the default stack size is computed as follows using values defined in FreeRTOSConfig.h and portmacro.h header files.
configPOSIX_STACK_SIZE * sizeof(portSTACK_TYPE)
Note that configPOSIX_STACK_SIZE
is a custom symbol defined the FreeRTOSConfig.h header file which is shipped in the SDK. The portmacro.h header file is shipped in the FreeRTOS distribution.
The priority is set to 1, which is the lowest priority allowed for a task other than the Idle task, which is priority 0.
Thread scheduling policy
int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param)
int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param)
The RTOS kernel uses a priority-based scheduler. The policy
parameter is ignored in these functions.
TI-POSIX on FreeRTOS
Best effort has been made to provide the same support between TI-RTOS and FreeRTOS. However, there are some exceptions, which are noted here.
There is no way to pass a stack to xTaskCreate()
pthread_attr_setstack() - not supported on FreeRTOS
Priority inheritance for mutexes is handled by FreeRTOS. The priority of a task that owns a mutex is temporarily raised, if a task of higher priority attempts to acquire the mutex. Therefore, mutex protocols are not supported on FreeRTOS.
pthread_mutexattr_getprotocol() - not supported for FreeRTOS
pthread_mutexattr_setprotocol() - not supported for FreeRTOS
pthread_mutexattr_getprioceiling() - not supported for FreeRTOS
pthread_mutexattr_setprioceiling() - not supported for FreeRTOS
Only CLOCK_REALTIME is supported with clock_settime()
.
timer_settime()
- this is a blocking call, unlike on TI-RTOS
Task cleanup is done by the Idle task in FreeRTOS. If pthreads are deleted, make sure the Idle task gets a chance to run to free allocated memory for the deleted thread.
Binary Semaphore
POSIX does not support a binary semaphore. That is, a semaphore which can be posted multiple times, but the count goes no greater than 1. The next pend will reduce the count to 0.
Fortunately, it is easy to build a binary semaphore using a mutex and condition variable. The following is a pseudo code example.
struct binary_semaphore {
pthread_mutex_t mutex;
pthread_cond_t cvar;
int v;
};
void mysem_post(struct binary_semaphore *p)
{
pthread_mutex_lock(&p->mutex);
p->v = 1;
pthread_cond_signal(&p->cvar);
pthread_mutex_unlock(&p->mutex);
}
void mysem_pend(struct binar_semaphore *p)
{
pthread_mutex_lock(&p->mutex);
while (!p->v) {
pthread_cond_wait(&p->cvar, &p->mutex);
}
p->v = 0;
pthread_mutex_unlock(&p->mutex);
}