From b513d37cf2fc33c2dd20021316533feaac0bef23 Mon Sep 17 00:00:00 2001 From: Meco Man <920369182@qq.com> Date: Sun, 17 Oct 2021 17:19:12 -0400 Subject: [libc][posix] create 'posix' folder and move related files into it --- components/libc/aio/SConscript | 11 - components/libc/aio/posix_aio.c | 459 ------------- components/libc/aio/posix_aio.h | 47 -- components/libc/mmap/SConscript | 13 - components/libc/mmap/posix_mmap.c | 67 -- components/libc/posix/SConscript | 15 + components/libc/posix/aio/SConscript | 11 + components/libc/posix/aio/posix_aio.c | 459 +++++++++++++ components/libc/posix/aio/posix_aio.h | 47 ++ components/libc/posix/mmap/SConscript | 13 + components/libc/posix/mmap/posix_mmap.c | 67 ++ components/libc/posix/pthreads/SConscript | 22 + components/libc/posix/pthreads/mqueue.c | 331 ++++++++++ components/libc/posix/pthreads/mqueue.h | 59 ++ components/libc/posix/pthreads/posix_types.h | 27 + components/libc/posix/pthreads/pthread.c | 748 ++++++++++++++++++++++ components/libc/posix/pthreads/pthread.h | 277 ++++++++ components/libc/posix/pthreads/pthread_attr.c | 207 ++++++ components/libc/posix/pthreads/pthread_barrier.c | 110 ++++ components/libc/posix/pthreads/pthread_cond.c | 235 +++++++ components/libc/posix/pthreads/pthread_internal.h | 70 ++ components/libc/posix/pthreads/pthread_mutex.c | 248 +++++++ components/libc/posix/pthreads/pthread_rwlock.c | 340 ++++++++++ components/libc/posix/pthreads/pthread_spin.c | 69 ++ components/libc/posix/pthreads/pthread_tls.c | 107 ++++ components/libc/posix/pthreads/sched.c | 42 ++ components/libc/posix/pthreads/sched.h | 40 ++ components/libc/posix/pthreads/semaphore.c | 387 +++++++++++ components/libc/posix/pthreads/semaphore.h | 43 ++ components/libc/posix/signal/SConscript | 13 + components/libc/posix/signal/posix_signal.c | 116 ++++ components/libc/posix/signal/posix_signal.h | 61 ++ components/libc/posix/termios/SConscript | 13 + components/libc/posix/termios/posix_termios.c | 129 ++++ components/libc/posix/termios/posix_termios.h | 213 ++++++ components/libc/pthreads/SConscript | 22 - components/libc/pthreads/mqueue.c | 331 ---------- components/libc/pthreads/mqueue.h | 59 -- components/libc/pthreads/posix_types.h | 27 - components/libc/pthreads/pthread.c | 748 ---------------------- components/libc/pthreads/pthread.h | 277 -------- components/libc/pthreads/pthread_attr.c | 207 ------ components/libc/pthreads/pthread_barrier.c | 110 ---- components/libc/pthreads/pthread_cond.c | 235 ------- components/libc/pthreads/pthread_internal.h | 70 -- components/libc/pthreads/pthread_mutex.c | 248 ------- components/libc/pthreads/pthread_rwlock.c | 340 ---------- components/libc/pthreads/pthread_spin.c | 69 -- components/libc/pthreads/pthread_tls.c | 107 ---- components/libc/pthreads/sched.c | 42 -- components/libc/pthreads/sched.h | 40 -- components/libc/pthreads/semaphore.c | 387 ----------- components/libc/pthreads/semaphore.h | 43 -- components/libc/signal/SConscript | 13 - components/libc/signal/posix_signal.c | 116 ---- components/libc/signal/posix_signal.h | 61 -- components/libc/termios/SConscript | 13 - components/libc/termios/posix_termios.c | 129 ---- components/libc/termios/posix_termios.h | 213 ------ 59 files changed, 4519 insertions(+), 4504 deletions(-) delete mode 100644 components/libc/aio/SConscript delete mode 100644 components/libc/aio/posix_aio.c delete mode 100644 components/libc/aio/posix_aio.h delete mode 100644 components/libc/mmap/SConscript delete mode 100644 components/libc/mmap/posix_mmap.c create mode 100644 components/libc/posix/SConscript create mode 100644 components/libc/posix/aio/SConscript create mode 100644 components/libc/posix/aio/posix_aio.c create mode 100644 components/libc/posix/aio/posix_aio.h create mode 100644 components/libc/posix/mmap/SConscript create mode 100644 components/libc/posix/mmap/posix_mmap.c create mode 100644 components/libc/posix/pthreads/SConscript create mode 100644 components/libc/posix/pthreads/mqueue.c create mode 100644 components/libc/posix/pthreads/mqueue.h create mode 100644 components/libc/posix/pthreads/posix_types.h create mode 100644 components/libc/posix/pthreads/pthread.c create mode 100644 components/libc/posix/pthreads/pthread.h create mode 100644 components/libc/posix/pthreads/pthread_attr.c create mode 100644 components/libc/posix/pthreads/pthread_barrier.c create mode 100644 components/libc/posix/pthreads/pthread_cond.c create mode 100644 components/libc/posix/pthreads/pthread_internal.h create mode 100644 components/libc/posix/pthreads/pthread_mutex.c create mode 100644 components/libc/posix/pthreads/pthread_rwlock.c create mode 100644 components/libc/posix/pthreads/pthread_spin.c create mode 100644 components/libc/posix/pthreads/pthread_tls.c create mode 100644 components/libc/posix/pthreads/sched.c create mode 100644 components/libc/posix/pthreads/sched.h create mode 100644 components/libc/posix/pthreads/semaphore.c create mode 100644 components/libc/posix/pthreads/semaphore.h create mode 100644 components/libc/posix/signal/SConscript create mode 100644 components/libc/posix/signal/posix_signal.c create mode 100644 components/libc/posix/signal/posix_signal.h create mode 100644 components/libc/posix/termios/SConscript create mode 100644 components/libc/posix/termios/posix_termios.c create mode 100644 components/libc/posix/termios/posix_termios.h delete mode 100644 components/libc/pthreads/SConscript delete mode 100644 components/libc/pthreads/mqueue.c delete mode 100644 components/libc/pthreads/mqueue.h delete mode 100644 components/libc/pthreads/posix_types.h delete mode 100644 components/libc/pthreads/pthread.c delete mode 100644 components/libc/pthreads/pthread.h delete mode 100644 components/libc/pthreads/pthread_attr.c delete mode 100644 components/libc/pthreads/pthread_barrier.c delete mode 100644 components/libc/pthreads/pthread_cond.c delete mode 100644 components/libc/pthreads/pthread_internal.h delete mode 100644 components/libc/pthreads/pthread_mutex.c delete mode 100644 components/libc/pthreads/pthread_rwlock.c delete mode 100644 components/libc/pthreads/pthread_spin.c delete mode 100644 components/libc/pthreads/pthread_tls.c delete mode 100644 components/libc/pthreads/sched.c delete mode 100644 components/libc/pthreads/sched.h delete mode 100644 components/libc/pthreads/semaphore.c delete mode 100644 components/libc/pthreads/semaphore.h delete mode 100644 components/libc/signal/SConscript delete mode 100644 components/libc/signal/posix_signal.c delete mode 100644 components/libc/signal/posix_signal.h delete mode 100644 components/libc/termios/SConscript delete mode 100644 components/libc/termios/posix_termios.c delete mode 100644 components/libc/termios/posix_termios.h diff --git a/components/libc/aio/SConscript b/components/libc/aio/SConscript deleted file mode 100644 index f10462e9c4..0000000000 --- a/components/libc/aio/SConscript +++ /dev/null @@ -1,11 +0,0 @@ -# RT-Thread building script for component - -from building import * - -cwd = GetCurrentDir() -src = Glob('*.c') + Glob('*.cpp') -CPPPATH = [cwd] - -group = DefineGroup('libc', src, depend = ['RT_USING_POSIX', 'RT_USING_POSIX_AIO'], CPPPATH = CPPPATH) - -Return('group') diff --git a/components/libc/aio/posix_aio.c b/components/libc/aio/posix_aio.c deleted file mode 100644 index 66cced8687..0000000000 --- a/components/libc/aio/posix_aio.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017/12/30 Bernard The first version. - */ - -#include -#include -#include -#include "posix_aio.h" - -struct rt_workqueue* aio_queue = NULL; - -/** - * The aio_cancel() function shall attempt to cancel one or more asynchronous I/O - * requests currently outstanding against file descriptor fildes. The aiocbp - * argument points to the asynchronous I/O control block for a particular request - * to be canceled. If aiocbp is NULL, then all outstanding cancelable asynchronous - * I/O requests against fildes shall be canceled. - * - * Normal asynchronous notification shall occur for asynchronous I/O operations - * that are successfully canceled. If there are requests that cannot be canceled, - * then the normal asynchronous completion process shall take place for those - * requests when they are completed. - * - * For requested operations that are successfully canceled, the associated error - * status shall be set to [ECANCELED] and the return status shall be -1. For - * requested operations that are not successfully canceled, the aiocbp shall not - * be modified by aio_cancel(). - * - * If aiocbp is not NULL, then if fildes does not have the same value as the file - * descriptor with which the asynchronous operation was initiated, unspecified results occur. - * - * Which operations are cancelable is implementation-defined. - */ -int aio_cancel(int fd, struct aiocb *cb) -{ - rt_err_t ret; - - if (!cb) return -EINVAL; - if (cb->aio_fildes != fd) return -EINVAL; - - ret = rt_workqueue_cancel_work_sync(aio_queue, &(cb->aio_work)); - if (ret == RT_EOK) - { - errno = -ECANCELED; - return -1; - } - - return 0; -} - -/** - * The aio_error() function shall return the error status associated with the - * aiocb structure referenced by the aiocbp argument. The error status for an - * asynchronous I/O operation is the errno value that would be set by the corresponding - * read(), write(), - */ -int aio_error (const struct aiocb *cb) -{ - if (cb) - { - return cb->aio_result; - } - - return -EINVAL; -} - -/** - * The aio_fsync() function shall asynchronously perform a file synchronization - * operation, as specified by the op argument, for I/O operations associated with - * the file indicated by the file descriptor aio_fildes member of the aiocb - * structure referenced by the aiocbp argument and queued at the time of the - * call to aio_fsync(). The function call shall return when the synchronization - * request has been initiated or queued to the file or device (even when the data - * cannot be synchronized immediately). - * - * option: If op is O_DSYNC, all currently queued I/O operations shall be completed - * as if by a call to fdatasync(); that is, as defined for synchronized I/O data - * integrity completion. - * - * option: If op is O_SYNC, all currently queued I/O operations shall be completed - * as if by a call to fsync(); that is, as defined for synchronized I/O file integrity - * completion. If the aio_fsync() function fails, or if the operation queued by - * aio_fsync() fails, then outstanding I/O operations are not guaranteed to have - * been completed. - * - * If aio_fsync() succeeds, then it is only the I/O that was queued at the time - * of the call to aio_fsync() that is guaranteed to be forced to the relevant - * completion state. The completion of subsequent I/O on the file descriptor is - * not guaranteed to be completed in a synchronized fashion. - * - * The aiocbp argument refers to an asynchronous I/O control block. The aiocbp - * value may be used as an argument to aio_error() and aio_return() in order to - * determine the error status and return status, respectively, of the asynchronous - * operation while it is proceeding. When the request is queued, the error status - * for the operation is [EINPROGRESS]. When all data has been successfully transferred, - * the error status shall be reset to reflect the success or failure of the operation. - * If the operation does not complete successfully, the error status for the - * operation shall be set to indicate the error. The aio_sigevent member determines - * the asynchronous notification to occur as specified in Signal Generation and - * Delivery when all operations have achieved synchronized I/O completion. All - * other members of the structure referenced by aiocbp are ignored. If the control - * block referenced by aiocbp becomes an illegal address prior to asynchronous - * I/O completion, then the behavior is undefined. - * - * If the aio_fsync() function fails or aiocbp indicates an error condition, - * data is not guaranteed to have been successfully transferred. - */ -static void aio_fync_work(struct rt_work* work, void* work_data) -{ - int result; - rt_ubase_t level; - struct aiocb *cb = (struct aiocb*)work_data; - - RT_ASSERT(cb != RT_NULL); - - result = fsync(cb->aio_fildes); - /* modify result */ - level = rt_hw_interrupt_disable(); - if (result < 0) - cb->aio_result = errno; - else - cb->aio_result = 0; - rt_hw_interrupt_enable(level); - - return ; -} - -int aio_fsync(int op, struct aiocb *cb) -{ - rt_ubase_t level; - if (!cb) return -EINVAL; - - level = rt_hw_interrupt_disable(); - cb->aio_result = -EINPROGRESS; - rt_hw_interrupt_enable(level); - - rt_work_init(&(cb->aio_work), aio_fync_work, cb); - rt_workqueue_dowork(aio_queue, &(cb->aio_work)); - - return 0; -} - -static void aio_read_work(struct rt_work* work, void* work_data) -{ - int len; - rt_ubase_t level; - uint8_t *buf_ptr; - struct aiocb *cb = (struct aiocb*)work_data; - - buf_ptr = (uint8_t*)cb->aio_buf; - - /* seek to offset */ - lseek(cb->aio_fildes, cb->aio_offset, SEEK_SET); - len = read(cb->aio_fildes, &buf_ptr[cb->aio_offset], cb->aio_nbytes); - - /* modify result */ - level = rt_hw_interrupt_disable(); - if (len <= 0) - cb->aio_result = errno; - else - cb->aio_result = len; - rt_hw_interrupt_enable(level); - - return ; -} - -/** - * The aio_read() function shall read aiocbp->aio_nbytes from the file associated - * with aiocbp->aio_fildes into the buffer pointed to by aiocbp->aio_buf. The - * function call shall return when the read request has been initiated or queued - * to the file or device (even when the data cannot be delivered immediately). - * - * If prioritized I/O is supported for this file, then the asynchronous operation - * shall be submitted at a priority equal to a base scheduling priority minus - * aiocbp->aio_reqprio. If Thread Execution Scheduling is not supported, then - * the base scheduling priority is that of the calling process; - * - * otherwise, the base scheduling priority is that of the calling thread. - * - * The aiocbp value may be used as an argument to aio_error() and aio_return() - * in order to determine the error status and return status, respectively, of - * the asynchronous operation while it is proceeding. If an error condition is - * encountered during queuing, the function call shall return without having - * initiated or queued the request. The requested operation takes place at the - * absolute position in the file as given by aio_offset, as if lseek() were called - * immediately prior to the operation with an offset equal to aio_offset and a - * whence equal to SEEK_SET. After a successful call to enqueue an asynchronous - * I/O operation, the value of the file offset for the file is unspecified. - * - * The aio_sigevent member specifies the notification which occurs when the - * request is completed. - * - * The aiocbp->aio_lio_opcode field shall be ignored by aio_read(). - * - * The aiocbp argument points to an aiocb structure. If the buffer pointed to by - * aiocbp->aio_buf or the control block pointed to by aiocbp becomes an illegal - * address prior to asynchronous I/O completion, then the behavior is undefined. - * - * Simultaneous asynchronous operations using the same aiocbp produce undefined - * results. - * - * If synchronized I/O is enabled on the file associated with aiocbp->aio_fildes, - * the behavior of this function shall be according to the definitions of synchronized - * I/O data integrity completion and synchronized I/O file integrity completion. - * - * For any system action that changes the process memory space while an asynchronous - * I/O is outstanding to the address range being changed, the result of that action - * is undefined. - * - * For regular files, no data transfer shall occur past the offset maximum - * established in the open file description associated with aiocbp->aio_fildes. - * - */ -int aio_read(struct aiocb *cb) -{ - rt_ubase_t level; - - if (!cb) return -EINVAL; - if (cb->aio_offset < 0) return -EINVAL; - - level = rt_hw_interrupt_disable(); - cb->aio_result = -EINPROGRESS; - rt_hw_interrupt_enable(level); - - /* en-queue read work */ - rt_work_init(&(cb->aio_work), aio_read_work, cb); - rt_workqueue_dowork(aio_queue, &(cb->aio_work)); - - return 0; -} - -/** - * The aio_return() function shall return the return status associated with the - * aiocb structure referenced by the aiocbp argument. The return status for an - * asynchronous I/O operation is the value that would be returned by the corresponding - * read(), write(), or fsync() function call. If the error status for the operation - * is equal to [EINPROGRESS], then the return status for the operation is undefined. - * The aio_return() function may be called exactly once to retrieve the return - * status of a given asynchronous operation; thereafter, if the same aiocb structure - * is used in a call to aio_return() or aio_error(), an error may be returned. - * When the aiocb structure referred to by aiocbp is used to submit another asynchronous - * operation, then aio_return() may be successfully used to retrieve the return - * status of that operation. - */ -ssize_t aio_return(struct aiocb *cb) -{ - if (cb) - { - if (cb->aio_result < 0) - rt_set_errno(cb->aio_result); - - return cb->aio_result; - } - - return -EINVAL; -} - -/** - * The aio_suspend() function shall suspend the calling thread until at least - * one of the asynchronous I/O operations referenced by the list argument has - * completed, until a signal interrupts the function, or, if timeout is not NULL, - * until the time interval specified by timeout has passed. If any of the aiocb - * structures in the list correspond to completed asynchronous I/O operations - * (that is, the error status for the operation is not equal to [EINPROGRESS]) - * at the time of the call, the function shall return without suspending the - * calling thread. The list argument is an array of pointers to asynchronous I/O - * control blocks. The nent argument indicates the number of elements in the - * array. Each aiocb structure pointed to has been used in initiating an asynchronous - * I/O request via aio_read(), aio_write(), or lio_listio(). This array may - * contain null pointers, which are ignored. If this array contains pointers - * that refer to aiocb structures that have not been used in submitting asynchronous - * I/O, the effect is undefined. - * - * If the time interval indicated in the timespec structure pointed to by timeout - * passes before any of the I/O operations referenced by list are completed, then - * aio_suspend() shall return with an error. - */ -int aio_suspend(const struct aiocb *const list[], int nent, - const struct timespec *timeout) -{ - return -ENOSYS; -} - -static void aio_write_work(struct rt_work* work, void* work_data) -{ - int len, oflags, level; - uint8_t *buf_ptr; - struct aiocb *cb = (struct aiocb*)work_data; - - buf_ptr = (uint8_t*)cb->aio_buf; - - /* whether seek offset */ - oflags = fcntl(cb->aio_fildes, F_GETFL, 0); - if ((oflags & O_APPEND) == 0) - { - lseek(cb->aio_fildes, SEEK_SET, cb->aio_offset); - } - - /* write data */ - len = write(cb->aio_fildes, buf_ptr, cb->aio_nbytes); - - /* modify result */ - level = rt_hw_interrupt_disable(); - if (len <= 0) - cb->aio_result = errno; - else - cb->aio_result = len; - rt_hw_interrupt_enable(level); - - return; -} - -/** - * The aio_write() function shall write aiocbp->aio_nbytes to the file associated - * with aiocbp->aio_fildes from the buffer pointed to by aiocbp->aio_buf. The - * function shall return when the write request has been initiated or, at a minimum, - * queued to the file or device. - * - * The aiocbp argument may be used as an argument to aio_error() and aio_return() - * in order to determine the error status and return status, respectively, of the - * asynchronous operation while it is proceeding. - * - * The aiocbp argument points to an aiocb structure. If the buffer pointed to by - * aiocbp->aio_buf or the control block pointed to by aiocbp becomes an illegal - * address prior to asynchronous I/O completion, then the behavior is undefined. - * - * If O_APPEND is not set for the file descriptor aio_fildes, then the requested - * operation shall take place at the absolute position in the file as given by - * aio_offset, as if lseek() were called immediately prior to the operation with - * an offset equal to aio_offset and a whence equal to SEEK_SET. If O_APPEND is - * set for the file descriptor, or if aio_fildes is associated with a device that - * is incapable of seeking, write operations append to the file in the same order - * as the calls were made, except under circumstances described in Asynchronous - * I/O. After a successful call to enqueue an asynchronous I/O operation, the value - * of the file offset for the file is unspecified. - * - * The aio_sigevent member specifies the notification which occurs when the request - * is completed. - * - * The aiocbp->aio_lio_opcode field shall be ignored by aio_write(). - * - * Simultaneous asynchronous operations using the same aiocbp produce undefined - * results. - * - * If synchronized I/O is enabled on the file associated with aiocbp->aio_fildes, - * the behavior of this function shall be according to the definitions of synchronized - * I/O data integrity completion, and synchronized I/O file integrity completion. - * - * For regular files, no data transfer shall occur past the offset maximum established - * in the open file description associated with aiocbp->aio_fildes. - */ -int aio_write(struct aiocb *cb) -{ - int oflags; - rt_ubase_t level; - - if (!cb || (cb->aio_buf == NULL)) return -EINVAL; - - /* check access mode */ - oflags = fcntl(cb->aio_fildes, F_GETFL, 0); - if ((oflags & O_ACCMODE) != O_WRONLY || - (oflags & O_ACCMODE) != O_RDWR) - return -EINVAL; - - level = rt_hw_interrupt_disable(); - cb->aio_result = -EINPROGRESS; - rt_hw_interrupt_enable(level); - - rt_work_init(&(cb->aio_work), aio_write_work, cb); - rt_workqueue_dowork(aio_queue, &(cb->aio_work)); - - return 0; -} - -/** - * The lio_listio() function shall initiate a list of I/O requests with a single - * function call. - * - * The mode argument takes one of the values LIO_WAIT or LIO_NOWAIT declared in - * and determines whether the function returns when the I/O operations - * have been completed, or as soon as the operations have been queued. If the - * mode argument is LIO_WAIT, the function shall wait until all I/O is complete - * and the sig argument shall be ignored. - * - * If the mode argument is LIO_NOWAIT, the function shall return immediately, and - * asynchronous notification shall occur, according to the sig argument, when all - * the I/O operations complete. If sig is NULL, then no asynchronous notification - * shall occur. If sig is not NULL, asynchronous notification occurs as specified - * in Signal Generation and Delivery when all the requests in list have completed. - * - * The I/O requests enumerated by list are submitted in an unspecified order. - * - * The list argument is an array of pointers to aiocb structures. The array contains - * nent elements. The array may contain NULL elements, which shall be ignored. - * - * If the buffer pointed to by list or the aiocb structures pointed to by the - * elements of the array list become illegal addresses before all asynchronous I/O - * completed and, if necessary, the notification is sent, then the behavior is - * undefined. If the buffers pointed to by the aio_buf member of the aiocb structure - * pointed to by the elements of the array list become illegal addresses prior to - * the asynchronous I/O associated with that aiocb structure being completed, the - * behavior is undefined. - * - * The aio_lio_opcode field of each aiocb structure specifies the operation to be - * performed. The supported operations are LIO_READ, LIO_WRITE, and LIO_NOP; these - * symbols are defined in . The LIO_NOP operation causes the list entry to - * be ignored. If the aio_lio_opcode element is equal to LIO_READ, then an I/O operation - * is submitted as if by a call to aio_read() with the aiocbp equal to the address - * of the aiocb structure. If the aio_lio_opcode element is equal to LIO_WRITE, then - * an I/O operation is submitted as if by a call to aio_write() with the aiocbp equal - * to the address of the aiocb structure. - * - * The aio_fildes member specifies the file descriptor on which the operation is to - * be performed. - * - * The aio_buf member specifies the address of the buffer to or from which the data - * is transferred. - * - * The aio_nbytes member specifies the number of bytes of data to be transferred. - * - * The members of the aiocb structure further describe the I/O operation to be - * performed, in a manner identical to that of the corresponding aiocb structure - * when used by the aio_read() and aio_write() functions. - * - * The nent argument specifies how many elements are members of the list; that is, - * the length of the array. - * - * The behavior of this function is altered according to the definitions of synchronized - * I/O data integrity completion and synchronized I/O file integrity completion if - * synchronized I/O is enabled on the file associated with aio_fildes. - * - * For regular files, no data transfer shall occur past the offset maximum established - * in the open file description associated with aiocbp->aio_fildes. - * - * If sig->sigev_notify is SIGEV_THREAD and sig->sigev_notify_attributes is a - * non-null pointer and the block pointed to by this pointer becomes an illegal - * address prior to all asynchronous I/O being completed, then the behavior is - * undefined. - */ -int lio_listio(int mode, struct aiocb * const list[], int nent, - struct sigevent *sig) -{ - return -ENOSYS; -} - -int aio_system_init(void) -{ - aio_queue = rt_workqueue_create("aio", 2048, RT_THREAD_PRIORITY_MAX/2); - RT_ASSERT(aio_queue != NULL); - - return 0; -} -INIT_COMPONENT_EXPORT(aio_system_init); diff --git a/components/libc/aio/posix_aio.h b/components/libc/aio/posix_aio.h deleted file mode 100644 index 4e25e1d15b..0000000000 --- a/components/libc/aio/posix_aio.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017/12/30 Bernard The first version. - */ - -#ifndef POSIX_AIO_H__ -#define POSIX_AIO_H__ - -#include -#include -#include - -struct aiocb -{ - int aio_fildes; /* File descriptor. */ - off_t aio_offset; /* File offset. */ - - volatile void *aio_buf; /* Location of buffer. */ - size_t aio_nbytes; /* Length of transfer. */ - int aio_reqprio; /* Request priority offset. */ - struct sigevent aio_sigevent; /* Signal number and value. */ - int aio_lio_opcode; /* Operation to be performed. */ - - int aio_result; - struct rt_work aio_work; -}; - -int aio_cancel(int fd, struct aiocb *cb); -int aio_error (const struct aiocb *cb); - -int aio_fsync(int op, struct aiocb *cb); - -int aio_read(struct aiocb *cb); -ssize_t aio_return(struct aiocb *cb); -int aio_suspend(const struct aiocb *const list[], int nent, - const struct timespec *timeout); -int aio_write(struct aiocb *cb); - -int lio_listio(int mode, struct aiocb * const list[], int nent, - struct sigevent *sig); - -#endif diff --git a/components/libc/mmap/SConscript b/components/libc/mmap/SConscript deleted file mode 100644 index 1a36a15710..0000000000 --- a/components/libc/mmap/SConscript +++ /dev/null @@ -1,13 +0,0 @@ -# RT-Thread building script for component - -from building import * - -cwd = GetCurrentDir() -src = Glob('*.c') + Glob('*.cpp') -CPPPATH = [cwd] - -group = DefineGroup('libc', src, - depend = ['RT_USING_DFS', 'RT_USING_POSIX_MMAP'], - CPPPATH = CPPPATH) - -Return('group') diff --git a/components/libc/mmap/posix_mmap.c b/components/libc/mmap/posix_mmap.c deleted file mode 100644 index e68b82e640..0000000000 --- a/components/libc/mmap/posix_mmap.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017/11/30 Bernard The first version. - */ - -#include -#include - -#include -#include - -#include - -void *mmap(void *addr, size_t length, int prot, int flags, - int fd, off_t offset) -{ - uint8_t *mem; - - if (addr) - { - mem = addr; - } - else mem = (uint8_t *)malloc(length); - - if (mem) - { - off_t cur; - size_t read_bytes; - - cur = lseek(fd, 0, SEEK_SET); - - lseek(fd, offset, SEEK_SET); - read_bytes = read(fd, mem, length); - if (read_bytes != length) - { - if (addr == RT_NULL) - { - /* read failed */ - free(mem); - mem = RT_NULL; - } - } - lseek(fd, cur, SEEK_SET); - - return mem; - } - - errno = ENOMEM; - - return MAP_FAILED; -} - -int munmap(void *addr, size_t length) -{ - if (addr) - { - free(addr); - return 0; - } - - return -1; -} diff --git a/components/libc/posix/SConscript b/components/libc/posix/SConscript new file mode 100644 index 0000000000..4c815c49b8 --- /dev/null +++ b/components/libc/posix/SConscript @@ -0,0 +1,15 @@ +# RT-Thread building script for bridge + +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/components/libc/posix/aio/SConscript b/components/libc/posix/aio/SConscript new file mode 100644 index 0000000000..f10462e9c4 --- /dev/null +++ b/components/libc/posix/aio/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('libc', src, depend = ['RT_USING_POSIX', 'RT_USING_POSIX_AIO'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/libc/posix/aio/posix_aio.c b/components/libc/posix/aio/posix_aio.c new file mode 100644 index 0000000000..66cced8687 --- /dev/null +++ b/components/libc/posix/aio/posix_aio.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017/12/30 Bernard The first version. + */ + +#include +#include +#include +#include "posix_aio.h" + +struct rt_workqueue* aio_queue = NULL; + +/** + * The aio_cancel() function shall attempt to cancel one or more asynchronous I/O + * requests currently outstanding against file descriptor fildes. The aiocbp + * argument points to the asynchronous I/O control block for a particular request + * to be canceled. If aiocbp is NULL, then all outstanding cancelable asynchronous + * I/O requests against fildes shall be canceled. + * + * Normal asynchronous notification shall occur for asynchronous I/O operations + * that are successfully canceled. If there are requests that cannot be canceled, + * then the normal asynchronous completion process shall take place for those + * requests when they are completed. + * + * For requested operations that are successfully canceled, the associated error + * status shall be set to [ECANCELED] and the return status shall be -1. For + * requested operations that are not successfully canceled, the aiocbp shall not + * be modified by aio_cancel(). + * + * If aiocbp is not NULL, then if fildes does not have the same value as the file + * descriptor with which the asynchronous operation was initiated, unspecified results occur. + * + * Which operations are cancelable is implementation-defined. + */ +int aio_cancel(int fd, struct aiocb *cb) +{ + rt_err_t ret; + + if (!cb) return -EINVAL; + if (cb->aio_fildes != fd) return -EINVAL; + + ret = rt_workqueue_cancel_work_sync(aio_queue, &(cb->aio_work)); + if (ret == RT_EOK) + { + errno = -ECANCELED; + return -1; + } + + return 0; +} + +/** + * The aio_error() function shall return the error status associated with the + * aiocb structure referenced by the aiocbp argument. The error status for an + * asynchronous I/O operation is the errno value that would be set by the corresponding + * read(), write(), + */ +int aio_error (const struct aiocb *cb) +{ + if (cb) + { + return cb->aio_result; + } + + return -EINVAL; +} + +/** + * The aio_fsync() function shall asynchronously perform a file synchronization + * operation, as specified by the op argument, for I/O operations associated with + * the file indicated by the file descriptor aio_fildes member of the aiocb + * structure referenced by the aiocbp argument and queued at the time of the + * call to aio_fsync(). The function call shall return when the synchronization + * request has been initiated or queued to the file or device (even when the data + * cannot be synchronized immediately). + * + * option: If op is O_DSYNC, all currently queued I/O operations shall be completed + * as if by a call to fdatasync(); that is, as defined for synchronized I/O data + * integrity completion. + * + * option: If op is O_SYNC, all currently queued I/O operations shall be completed + * as if by a call to fsync(); that is, as defined for synchronized I/O file integrity + * completion. If the aio_fsync() function fails, or if the operation queued by + * aio_fsync() fails, then outstanding I/O operations are not guaranteed to have + * been completed. + * + * If aio_fsync() succeeds, then it is only the I/O that was queued at the time + * of the call to aio_fsync() that is guaranteed to be forced to the relevant + * completion state. The completion of subsequent I/O on the file descriptor is + * not guaranteed to be completed in a synchronized fashion. + * + * The aiocbp argument refers to an asynchronous I/O control block. The aiocbp + * value may be used as an argument to aio_error() and aio_return() in order to + * determine the error status and return status, respectively, of the asynchronous + * operation while it is proceeding. When the request is queued, the error status + * for the operation is [EINPROGRESS]. When all data has been successfully transferred, + * the error status shall be reset to reflect the success or failure of the operation. + * If the operation does not complete successfully, the error status for the + * operation shall be set to indicate the error. The aio_sigevent member determines + * the asynchronous notification to occur as specified in Signal Generation and + * Delivery when all operations have achieved synchronized I/O completion. All + * other members of the structure referenced by aiocbp are ignored. If the control + * block referenced by aiocbp becomes an illegal address prior to asynchronous + * I/O completion, then the behavior is undefined. + * + * If the aio_fsync() function fails or aiocbp indicates an error condition, + * data is not guaranteed to have been successfully transferred. + */ +static void aio_fync_work(struct rt_work* work, void* work_data) +{ + int result; + rt_ubase_t level; + struct aiocb *cb = (struct aiocb*)work_data; + + RT_ASSERT(cb != RT_NULL); + + result = fsync(cb->aio_fildes); + /* modify result */ + level = rt_hw_interrupt_disable(); + if (result < 0) + cb->aio_result = errno; + else + cb->aio_result = 0; + rt_hw_interrupt_enable(level); + + return ; +} + +int aio_fsync(int op, struct aiocb *cb) +{ + rt_ubase_t level; + if (!cb) return -EINVAL; + + level = rt_hw_interrupt_disable(); + cb->aio_result = -EINPROGRESS; + rt_hw_interrupt_enable(level); + + rt_work_init(&(cb->aio_work), aio_fync_work, cb); + rt_workqueue_dowork(aio_queue, &(cb->aio_work)); + + return 0; +} + +static void aio_read_work(struct rt_work* work, void* work_data) +{ + int len; + rt_ubase_t level; + uint8_t *buf_ptr; + struct aiocb *cb = (struct aiocb*)work_data; + + buf_ptr = (uint8_t*)cb->aio_buf; + + /* seek to offset */ + lseek(cb->aio_fildes, cb->aio_offset, SEEK_SET); + len = read(cb->aio_fildes, &buf_ptr[cb->aio_offset], cb->aio_nbytes); + + /* modify result */ + level = rt_hw_interrupt_disable(); + if (len <= 0) + cb->aio_result = errno; + else + cb->aio_result = len; + rt_hw_interrupt_enable(level); + + return ; +} + +/** + * The aio_read() function shall read aiocbp->aio_nbytes from the file associated + * with aiocbp->aio_fildes into the buffer pointed to by aiocbp->aio_buf. The + * function call shall return when the read request has been initiated or queued + * to the file or device (even when the data cannot be delivered immediately). + * + * If prioritized I/O is supported for this file, then the asynchronous operation + * shall be submitted at a priority equal to a base scheduling priority minus + * aiocbp->aio_reqprio. If Thread Execution Scheduling is not supported, then + * the base scheduling priority is that of the calling process; + * + * otherwise, the base scheduling priority is that of the calling thread. + * + * The aiocbp value may be used as an argument to aio_error() and aio_return() + * in order to determine the error status and return status, respectively, of + * the asynchronous operation while it is proceeding. If an error condition is + * encountered during queuing, the function call shall return without having + * initiated or queued the request. The requested operation takes place at the + * absolute position in the file as given by aio_offset, as if lseek() were called + * immediately prior to the operation with an offset equal to aio_offset and a + * whence equal to SEEK_SET. After a successful call to enqueue an asynchronous + * I/O operation, the value of the file offset for the file is unspecified. + * + * The aio_sigevent member specifies the notification which occurs when the + * request is completed. + * + * The aiocbp->aio_lio_opcode field shall be ignored by aio_read(). + * + * The aiocbp argument points to an aiocb structure. If the buffer pointed to by + * aiocbp->aio_buf or the control block pointed to by aiocbp becomes an illegal + * address prior to asynchronous I/O completion, then the behavior is undefined. + * + * Simultaneous asynchronous operations using the same aiocbp produce undefined + * results. + * + * If synchronized I/O is enabled on the file associated with aiocbp->aio_fildes, + * the behavior of this function shall be according to the definitions of synchronized + * I/O data integrity completion and synchronized I/O file integrity completion. + * + * For any system action that changes the process memory space while an asynchronous + * I/O is outstanding to the address range being changed, the result of that action + * is undefined. + * + * For regular files, no data transfer shall occur past the offset maximum + * established in the open file description associated with aiocbp->aio_fildes. + * + */ +int aio_read(struct aiocb *cb) +{ + rt_ubase_t level; + + if (!cb) return -EINVAL; + if (cb->aio_offset < 0) return -EINVAL; + + level = rt_hw_interrupt_disable(); + cb->aio_result = -EINPROGRESS; + rt_hw_interrupt_enable(level); + + /* en-queue read work */ + rt_work_init(&(cb->aio_work), aio_read_work, cb); + rt_workqueue_dowork(aio_queue, &(cb->aio_work)); + + return 0; +} + +/** + * The aio_return() function shall return the return status associated with the + * aiocb structure referenced by the aiocbp argument. The return status for an + * asynchronous I/O operation is the value that would be returned by the corresponding + * read(), write(), or fsync() function call. If the error status for the operation + * is equal to [EINPROGRESS], then the return status for the operation is undefined. + * The aio_return() function may be called exactly once to retrieve the return + * status of a given asynchronous operation; thereafter, if the same aiocb structure + * is used in a call to aio_return() or aio_error(), an error may be returned. + * When the aiocb structure referred to by aiocbp is used to submit another asynchronous + * operation, then aio_return() may be successfully used to retrieve the return + * status of that operation. + */ +ssize_t aio_return(struct aiocb *cb) +{ + if (cb) + { + if (cb->aio_result < 0) + rt_set_errno(cb->aio_result); + + return cb->aio_result; + } + + return -EINVAL; +} + +/** + * The aio_suspend() function shall suspend the calling thread until at least + * one of the asynchronous I/O operations referenced by the list argument has + * completed, until a signal interrupts the function, or, if timeout is not NULL, + * until the time interval specified by timeout has passed. If any of the aiocb + * structures in the list correspond to completed asynchronous I/O operations + * (that is, the error status for the operation is not equal to [EINPROGRESS]) + * at the time of the call, the function shall return without suspending the + * calling thread. The list argument is an array of pointers to asynchronous I/O + * control blocks. The nent argument indicates the number of elements in the + * array. Each aiocb structure pointed to has been used in initiating an asynchronous + * I/O request via aio_read(), aio_write(), or lio_listio(). This array may + * contain null pointers, which are ignored. If this array contains pointers + * that refer to aiocb structures that have not been used in submitting asynchronous + * I/O, the effect is undefined. + * + * If the time interval indicated in the timespec structure pointed to by timeout + * passes before any of the I/O operations referenced by list are completed, then + * aio_suspend() shall return with an error. + */ +int aio_suspend(const struct aiocb *const list[], int nent, + const struct timespec *timeout) +{ + return -ENOSYS; +} + +static void aio_write_work(struct rt_work* work, void* work_data) +{ + int len, oflags, level; + uint8_t *buf_ptr; + struct aiocb *cb = (struct aiocb*)work_data; + + buf_ptr = (uint8_t*)cb->aio_buf; + + /* whether seek offset */ + oflags = fcntl(cb->aio_fildes, F_GETFL, 0); + if ((oflags & O_APPEND) == 0) + { + lseek(cb->aio_fildes, SEEK_SET, cb->aio_offset); + } + + /* write data */ + len = write(cb->aio_fildes, buf_ptr, cb->aio_nbytes); + + /* modify result */ + level = rt_hw_interrupt_disable(); + if (len <= 0) + cb->aio_result = errno; + else + cb->aio_result = len; + rt_hw_interrupt_enable(level); + + return; +} + +/** + * The aio_write() function shall write aiocbp->aio_nbytes to the file associated + * with aiocbp->aio_fildes from the buffer pointed to by aiocbp->aio_buf. The + * function shall return when the write request has been initiated or, at a minimum, + * queued to the file or device. + * + * The aiocbp argument may be used as an argument to aio_error() and aio_return() + * in order to determine the error status and return status, respectively, of the + * asynchronous operation while it is proceeding. + * + * The aiocbp argument points to an aiocb structure. If the buffer pointed to by + * aiocbp->aio_buf or the control block pointed to by aiocbp becomes an illegal + * address prior to asynchronous I/O completion, then the behavior is undefined. + * + * If O_APPEND is not set for the file descriptor aio_fildes, then the requested + * operation shall take place at the absolute position in the file as given by + * aio_offset, as if lseek() were called immediately prior to the operation with + * an offset equal to aio_offset and a whence equal to SEEK_SET. If O_APPEND is + * set for the file descriptor, or if aio_fildes is associated with a device that + * is incapable of seeking, write operations append to the file in the same order + * as the calls were made, except under circumstances described in Asynchronous + * I/O. After a successful call to enqueue an asynchronous I/O operation, the value + * of the file offset for the file is unspecified. + * + * The aio_sigevent member specifies the notification which occurs when the request + * is completed. + * + * The aiocbp->aio_lio_opcode field shall be ignored by aio_write(). + * + * Simultaneous asynchronous operations using the same aiocbp produce undefined + * results. + * + * If synchronized I/O is enabled on the file associated with aiocbp->aio_fildes, + * the behavior of this function shall be according to the definitions of synchronized + * I/O data integrity completion, and synchronized I/O file integrity completion. + * + * For regular files, no data transfer shall occur past the offset maximum established + * in the open file description associated with aiocbp->aio_fildes. + */ +int aio_write(struct aiocb *cb) +{ + int oflags; + rt_ubase_t level; + + if (!cb || (cb->aio_buf == NULL)) return -EINVAL; + + /* check access mode */ + oflags = fcntl(cb->aio_fildes, F_GETFL, 0); + if ((oflags & O_ACCMODE) != O_WRONLY || + (oflags & O_ACCMODE) != O_RDWR) + return -EINVAL; + + level = rt_hw_interrupt_disable(); + cb->aio_result = -EINPROGRESS; + rt_hw_interrupt_enable(level); + + rt_work_init(&(cb->aio_work), aio_write_work, cb); + rt_workqueue_dowork(aio_queue, &(cb->aio_work)); + + return 0; +} + +/** + * The lio_listio() function shall initiate a list of I/O requests with a single + * function call. + * + * The mode argument takes one of the values LIO_WAIT or LIO_NOWAIT declared in + * and determines whether the function returns when the I/O operations + * have been completed, or as soon as the operations have been queued. If the + * mode argument is LIO_WAIT, the function shall wait until all I/O is complete + * and the sig argument shall be ignored. + * + * If the mode argument is LIO_NOWAIT, the function shall return immediately, and + * asynchronous notification shall occur, according to the sig argument, when all + * the I/O operations complete. If sig is NULL, then no asynchronous notification + * shall occur. If sig is not NULL, asynchronous notification occurs as specified + * in Signal Generation and Delivery when all the requests in list have completed. + * + * The I/O requests enumerated by list are submitted in an unspecified order. + * + * The list argument is an array of pointers to aiocb structures. The array contains + * nent elements. The array may contain NULL elements, which shall be ignored. + * + * If the buffer pointed to by list or the aiocb structures pointed to by the + * elements of the array list become illegal addresses before all asynchronous I/O + * completed and, if necessary, the notification is sent, then the behavior is + * undefined. If the buffers pointed to by the aio_buf member of the aiocb structure + * pointed to by the elements of the array list become illegal addresses prior to + * the asynchronous I/O associated with that aiocb structure being completed, the + * behavior is undefined. + * + * The aio_lio_opcode field of each aiocb structure specifies the operation to be + * performed. The supported operations are LIO_READ, LIO_WRITE, and LIO_NOP; these + * symbols are defined in . The LIO_NOP operation causes the list entry to + * be ignored. If the aio_lio_opcode element is equal to LIO_READ, then an I/O operation + * is submitted as if by a call to aio_read() with the aiocbp equal to the address + * of the aiocb structure. If the aio_lio_opcode element is equal to LIO_WRITE, then + * an I/O operation is submitted as if by a call to aio_write() with the aiocbp equal + * to the address of the aiocb structure. + * + * The aio_fildes member specifies the file descriptor on which the operation is to + * be performed. + * + * The aio_buf member specifies the address of the buffer to or from which the data + * is transferred. + * + * The aio_nbytes member specifies the number of bytes of data to be transferred. + * + * The members of the aiocb structure further describe the I/O operation to be + * performed, in a manner identical to that of the corresponding aiocb structure + * when used by the aio_read() and aio_write() functions. + * + * The nent argument specifies how many elements are members of the list; that is, + * the length of the array. + * + * The behavior of this function is altered according to the definitions of synchronized + * I/O data integrity completion and synchronized I/O file integrity completion if + * synchronized I/O is enabled on the file associated with aio_fildes. + * + * For regular files, no data transfer shall occur past the offset maximum established + * in the open file description associated with aiocbp->aio_fildes. + * + * If sig->sigev_notify is SIGEV_THREAD and sig->sigev_notify_attributes is a + * non-null pointer and the block pointed to by this pointer becomes an illegal + * address prior to all asynchronous I/O being completed, then the behavior is + * undefined. + */ +int lio_listio(int mode, struct aiocb * const list[], int nent, + struct sigevent *sig) +{ + return -ENOSYS; +} + +int aio_system_init(void) +{ + aio_queue = rt_workqueue_create("aio", 2048, RT_THREAD_PRIORITY_MAX/2); + RT_ASSERT(aio_queue != NULL); + + return 0; +} +INIT_COMPONENT_EXPORT(aio_system_init); diff --git a/components/libc/posix/aio/posix_aio.h b/components/libc/posix/aio/posix_aio.h new file mode 100644 index 0000000000..4e25e1d15b --- /dev/null +++ b/components/libc/posix/aio/posix_aio.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017/12/30 Bernard The first version. + */ + +#ifndef POSIX_AIO_H__ +#define POSIX_AIO_H__ + +#include +#include +#include + +struct aiocb +{ + int aio_fildes; /* File descriptor. */ + off_t aio_offset; /* File offset. */ + + volatile void *aio_buf; /* Location of buffer. */ + size_t aio_nbytes; /* Length of transfer. */ + int aio_reqprio; /* Request priority offset. */ + struct sigevent aio_sigevent; /* Signal number and value. */ + int aio_lio_opcode; /* Operation to be performed. */ + + int aio_result; + struct rt_work aio_work; +}; + +int aio_cancel(int fd, struct aiocb *cb); +int aio_error (const struct aiocb *cb); + +int aio_fsync(int op, struct aiocb *cb); + +int aio_read(struct aiocb *cb); +ssize_t aio_return(struct aiocb *cb); +int aio_suspend(const struct aiocb *const list[], int nent, + const struct timespec *timeout); +int aio_write(struct aiocb *cb); + +int lio_listio(int mode, struct aiocb * const list[], int nent, + struct sigevent *sig); + +#endif diff --git a/components/libc/posix/mmap/SConscript b/components/libc/posix/mmap/SConscript new file mode 100644 index 0000000000..1a36a15710 --- /dev/null +++ b/components/libc/posix/mmap/SConscript @@ -0,0 +1,13 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('libc', src, + depend = ['RT_USING_DFS', 'RT_USING_POSIX_MMAP'], + CPPPATH = CPPPATH) + +Return('group') diff --git a/components/libc/posix/mmap/posix_mmap.c b/components/libc/posix/mmap/posix_mmap.c new file mode 100644 index 0000000000..e68b82e640 --- /dev/null +++ b/components/libc/posix/mmap/posix_mmap.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017/11/30 Bernard The first version. + */ + +#include +#include + +#include +#include + +#include + +void *mmap(void *addr, size_t length, int prot, int flags, + int fd, off_t offset) +{ + uint8_t *mem; + + if (addr) + { + mem = addr; + } + else mem = (uint8_t *)malloc(length); + + if (mem) + { + off_t cur; + size_t read_bytes; + + cur = lseek(fd, 0, SEEK_SET); + + lseek(fd, offset, SEEK_SET); + read_bytes = read(fd, mem, length); + if (read_bytes != length) + { + if (addr == RT_NULL) + { + /* read failed */ + free(mem); + mem = RT_NULL; + } + } + lseek(fd, cur, SEEK_SET); + + return mem; + } + + errno = ENOMEM; + + return MAP_FAILED; +} + +int munmap(void *addr, size_t length) +{ + if (addr) + { + free(addr); + return 0; + } + + return -1; +} diff --git a/components/libc/posix/pthreads/SConscript b/components/libc/posix/pthreads/SConscript new file mode 100644 index 0000000000..767b406d4c --- /dev/null +++ b/components/libc/posix/pthreads/SConscript @@ -0,0 +1,22 @@ +from building import * +from utils import VersionCmp + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] +CPPDEFINES = [] + +# only enable POSIX.1b-1993 Real-time extensions +libc_ver = GetDepend('LIBC_VERSION') +try: + ver = libc_ver.split(' ') + ver = ver[1] + if VersionCmp(ver, "2.5.0") == 1: + CPPDEFINES = ['_POSIX_C_SOURCE=199309L'] +except : + pass + +group = DefineGroup('libc', src, + depend = ['RT_USING_PTHREADS', 'RT_USING_LIBC'], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) + +Return('group') diff --git a/components/libc/posix/pthreads/mqueue.c b/components/libc/posix/pthreads/mqueue.c new file mode 100644 index 0000000000..6840164a68 --- /dev/null +++ b/components/libc/posix/pthreads/mqueue.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include +#include +#include "mqueue.h" +#include "pthread_internal.h" + +static mqd_t posix_mq_list = RT_NULL; +static struct rt_semaphore posix_mq_lock; +void posix_mq_system_init() +{ + rt_sem_init(&posix_mq_lock, "pmq", 1, RT_IPC_FLAG_FIFO); +} + +rt_inline void posix_mq_insert(mqd_t pmq) +{ + pmq->next = posix_mq_list; + posix_mq_list = pmq; +} + +static void posix_mq_delete(mqd_t pmq) +{ + mqd_t iter; + if (posix_mq_list == pmq) + { + posix_mq_list = pmq->next; + + rt_mq_delete(pmq->mq); + rt_free(pmq); + + return; + } + for (iter = posix_mq_list; iter->next != RT_NULL; iter = iter->next) + { + if (iter->next == pmq) + { + /* delete this mq */ + if (pmq->next != RT_NULL) + iter->next = pmq->next; + else + iter->next = RT_NULL; + + /* delete RT-Thread mqueue */ + rt_mq_delete(pmq->mq); + rt_free(pmq); + + return ; + } + } +} + +static mqd_t posix_mq_find(const char* name) +{ + mqd_t iter; + rt_object_t object; + + for (iter = posix_mq_list; iter != RT_NULL; iter = iter->next) + { + object = (rt_object_t)(iter->mq); + + if (strncmp(object->name, name, RT_NAME_MAX) == 0) + { + return iter; + } + } + + return RT_NULL; +} + +int mq_setattr(mqd_t mqdes, + const struct mq_attr *mqstat, + struct mq_attr *omqstat) +{ + rt_set_errno(-RT_ERROR); + + return -1; +} +RTM_EXPORT(mq_setattr); + +int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat) +{ + if ((mqdes == RT_NULL) || mqstat == RT_NULL) + { + rt_set_errno(EBADF); + + return -1; + } + + mqstat->mq_maxmsg = mqdes->mq->max_msgs; + mqstat->mq_msgsize = mqdes->mq->msg_size; + mqstat->mq_curmsgs = 0; + mqstat->mq_flags = 0; + + return 0; +} +RTM_EXPORT(mq_getattr); + +mqd_t mq_open(const char *name, int oflag, ...) +{ + mqd_t mqdes; + va_list arg; + mode_t mode; + struct mq_attr *attr = RT_NULL; + + /* lock posix mqueue list */ + rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); + + mqdes = RT_NULL; + if (oflag & O_CREAT) + { + va_start(arg, oflag); + mode = (mode_t)va_arg(arg, unsigned int); + mode = mode; + attr = (struct mq_attr *)va_arg(arg, struct mq_attr *); + va_end(arg); + + if (oflag & O_EXCL) + { + if (posix_mq_find(name) != RT_NULL) + { + rt_set_errno(EEXIST); + goto __return; + } + } + mqdes = (mqd_t) rt_malloc (sizeof(struct mqdes)); + if (mqdes == RT_NULL) + { + rt_set_errno(ENFILE); + goto __return; + } + + /* create RT-Thread message queue */ + mqdes->mq = rt_mq_create(name, attr->mq_msgsize, attr->mq_maxmsg, RT_IPC_FLAG_FIFO); + if (mqdes->mq == RT_NULL) /* create failed */ + { + rt_set_errno(ENFILE); + goto __return; + } + /* initialize reference count */ + mqdes->refcount = 1; + mqdes->unlinked = 0; + + /* insert mq to posix mq list */ + posix_mq_insert(mqdes); + } + else + { + /* find mqueue */ + mqdes = posix_mq_find(name); + if (mqdes != RT_NULL) + { + mqdes->refcount ++; /* increase reference count */ + } + else + { + rt_set_errno(ENOENT); + goto __return; + } + } + rt_sem_release(&posix_mq_lock); + + return mqdes; + +__return: + /* release lock */ + rt_sem_release(&posix_mq_lock); + + /* release allocated memory */ + if (mqdes != RT_NULL) + { + if (mqdes->mq != RT_NULL) + { + /* delete RT-Thread message queue */ + rt_mq_delete(mqdes->mq); + } + rt_free(mqdes); + } + return RT_NULL; +} +RTM_EXPORT(mq_open); + +ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio) +{ + rt_err_t result; + + if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_mq_recv(mqdes->mq, msg_ptr, msg_len, RT_WAITING_FOREVER); + if (result == RT_EOK) + return msg_len; + + rt_set_errno(EBADF); + return -1; +} +RTM_EXPORT(mq_receive); + +int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio) +{ + rt_err_t result; + + if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_mq_send(mqdes->mq, (void*)msg_ptr, msg_len); + if (result == RT_EOK) + return 0; + + rt_set_errno(EBADF); + + return -1; +} +RTM_EXPORT(mq_send); + +ssize_t mq_timedreceive(mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned *msg_prio, + const struct timespec *abs_timeout) +{ + int tick; + rt_err_t result; + + /* parameters check */ + if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + tick = rt_timespec_to_tick(abs_timeout); + + result = rt_mq_recv(mqdes->mq, msg_ptr, msg_len, tick); + if (result == RT_EOK) + return msg_len; + + if (result == -RT_ETIMEOUT) + rt_set_errno(ETIMEDOUT); + else + rt_set_errno(EBADMSG); + + return -1; +} +RTM_EXPORT(mq_timedreceive); + +int mq_timedsend(mqd_t mqdes, + const char *msg_ptr, + size_t msg_len, + unsigned msg_prio, + const struct timespec *abs_timeout) +{ + /* RT-Thread does not support timed send */ + return mq_send(mqdes, msg_ptr, msg_len, msg_prio); +} +RTM_EXPORT(mq_timedsend); + +int mq_notify(mqd_t mqdes, const struct sigevent *notification) +{ + rt_set_errno(-RT_ERROR); + + return -1; +} +RTM_EXPORT(mq_notify); + +int mq_close(mqd_t mqdes) +{ + if (mqdes == RT_NULL) + { + rt_set_errno(EINVAL); + + return -1; + } + + /* lock posix mqueue list */ + rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); + mqdes->refcount --; + if (mqdes->refcount == 0) + { + /* delete from posix mqueue list */ + if (mqdes->unlinked) + posix_mq_delete(mqdes); + } + rt_sem_release(&posix_mq_lock); + + return 0; +} +RTM_EXPORT(mq_close); + +int mq_unlink(const char *name) +{ + mqd_t pmq; + + /* lock posix mqueue list */ + rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); + pmq = posix_mq_find(name); + if (pmq != RT_NULL) + { + pmq->unlinked = 1; + if (pmq->refcount == 0) + { + /* remove this mqueue */ + posix_mq_delete(pmq); + } + rt_sem_release(&posix_mq_lock); + + return 0; + } + rt_sem_release(&posix_mq_lock); + + /* no this entry */ + rt_set_errno(ENOENT); + + return -1; +} +RTM_EXPORT(mq_unlink); diff --git a/components/libc/posix/pthreads/mqueue.h b/components/libc/posix/pthreads/mqueue.h new file mode 100644 index 0000000000..5152bfad29 --- /dev/null +++ b/components/libc/posix/pthreads/mqueue.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __MQUEUE_H__ +#define __MQUEUE_H__ + +#include +#include + +struct mqdes +{ + /* reference count and unlinked */ + rt_uint16_t refcount; + rt_uint16_t unlinked; + + /* RT-Thread message queue */ + rt_mq_t mq; + /* next posix mqueue */ + struct mqdes* next; +}; +typedef struct mqdes* mqd_t; + +struct mq_attr +{ + long mq_flags; /* Message queue flags. */ + long mq_maxmsg; /* Maximum number of messages. */ + long mq_msgsize; /* Maximum message size. */ + long mq_curmsgs; /* Number of messages currently queued. */ +}; + +int mq_close(mqd_t mqdes); +int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); +int mq_notify(mqd_t mqdes, const struct sigevent *notification); +mqd_t mq_open(const char *name, int oflag, ...); +ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); +int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); +int mq_setattr(mqd_t mqdes, + const struct mq_attr *mqstat, + struct mq_attr *omqstat); +ssize_t mq_timedreceive(mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned *msg_prio, + const struct timespec *abs_timeout); +int mq_timedsend(mqd_t mqdes, + const char *msg_ptr, + size_t msg_len, + unsigned msg_prio, + const struct timespec *abs_timeout); + +int mq_unlink(const char *name); + +#endif diff --git a/components/libc/posix/pthreads/posix_types.h b/components/libc/posix/pthreads/posix_types.h new file mode 100644 index 0000000000..5838e8b370 --- /dev/null +++ b/components/libc/posix/pthreads/posix_types.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2013-12-23 Bernard Add the checking for ESHUTDOWN + */ + +#ifndef __POSIX_TYPES_H__ +#define __POSIX_TYPES_H__ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#endif + diff --git a/components/libc/posix/pthreads/pthread.c b/components/libc/posix/pthreads/pthread.c new file mode 100644 index 0000000000..b0bf39dff6 --- /dev/null +++ b/components/libc/posix/pthreads/pthread.c @@ -0,0 +1,748 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-01-26 Bernard Fix pthread_detach issue for a none-joinable + * thread. + * 2019-02-07 Bernard Add _pthread_destroy to release pthread resource. + */ + +#include +#include +#include +#include +#include "pthread_internal.h" + +RT_DEFINE_SPINLOCK(pth_lock); +_pthread_data_t *pth_table[PTHREAD_NUM_MAX] = {NULL}; + +_pthread_data_t *_pthread_get_data(pthread_t thread) +{ + RT_DECLARE_SPINLOCK(pth_lock); + _pthread_data_t *ptd; + + if (thread >= PTHREAD_NUM_MAX) return NULL; + + rt_hw_spin_lock(&pth_lock); + ptd = pth_table[thread]; + rt_hw_spin_unlock(&pth_lock); + + if (ptd && ptd->magic == PTHREAD_MAGIC) return ptd; + + return NULL; +} + +pthread_t _pthread_data_get_pth(_pthread_data_t *ptd) +{ + int index; + RT_DECLARE_SPINLOCK(pth_lock); + + rt_hw_spin_lock(&pth_lock); + for (index = 0; index < PTHREAD_NUM_MAX; index ++) + { + if (pth_table[index] == ptd) break; + } + rt_hw_spin_unlock(&pth_lock); + + return index; +} + +pthread_t _pthread_data_create(void) +{ + int index; + _pthread_data_t *ptd = NULL; + RT_DECLARE_SPINLOCK(pth_lock); + + ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t)); + if (!ptd) return PTHREAD_NUM_MAX; + + memset(ptd, 0x0, sizeof(_pthread_data_t)); + ptd->canceled = 0; + ptd->cancelstate = PTHREAD_CANCEL_DISABLE; + ptd->canceltype = PTHREAD_CANCEL_DEFERRED; + ptd->magic = PTHREAD_MAGIC; + + rt_hw_spin_lock(&pth_lock); + for (index = 0; index < PTHREAD_NUM_MAX; index ++) + { + if (pth_table[index] == NULL) + { + pth_table[index] = ptd; + break; + } + } + rt_hw_spin_unlock(&pth_lock); + + /* full of pthreads, clean magic and release ptd */ + if (index == PTHREAD_NUM_MAX) + { + ptd->magic = 0x0; + rt_free(ptd); + } + + return index; +} + +void _pthread_data_destroy(pthread_t pth) +{ + RT_DECLARE_SPINLOCK(pth_lock); + + extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; + _pthread_data_t *ptd = _pthread_get_data(pth); + if (ptd) + { + /* destruct thread local key */ + if (ptd->tls != RT_NULL) + { + void *data; + rt_uint32_t index; + for (index = 0; index < PTHREAD_KEY_MAX; index ++) + { + if (_thread_keys[index].is_used) + { + data = ptd->tls[index]; + if (data && _thread_keys[index].destructor) + _thread_keys[index].destructor(data); + } + } + + /* release tls area */ + rt_free(ptd->tls); + ptd->tls = RT_NULL; + } + + /* remove from pthread table */ + rt_hw_spin_lock(&pth_lock); + pth_table[pth] = NULL; + rt_hw_spin_unlock(&pth_lock); + + /* delete joinable semaphore */ + if (ptd->joinable_sem != RT_NULL) + rt_sem_delete(ptd->joinable_sem); + + /* release thread resource */ + if (ptd->attr.stackaddr == RT_NULL) + { + /* release thread allocated stack */ + if (ptd->tid) + { + rt_free(ptd->tid->stack_addr); + } + } + /* clean stack addr pointer */ + if (ptd->tid) + ptd->tid->stack_addr = RT_NULL; + + /* + * if this thread create the local thread data, + * delete it + */ + if (ptd->tls != RT_NULL) rt_free(ptd->tls); + rt_free(ptd->tid); + + /* clean magic */ + ptd->magic = 0x0; + + /* free ptd */ + rt_free(ptd); + } +} + +int pthread_system_init(void) +{ + /* initialize key area */ + pthread_key_system_init(); + /* initialize posix mqueue */ + posix_mq_system_init(); + /* initialize posix semaphore */ + posix_sem_system_init(); + + return 0; +} +INIT_COMPONENT_EXPORT(pthread_system_init); + +static void _pthread_destroy(_pthread_data_t *ptd) +{ + pthread_t pth = _pthread_data_get_pth(ptd); + if (pth != PTHREAD_NUM_MAX) + { + _pthread_data_destroy(pth); + } + + return; +} + +static void _pthread_cleanup(rt_thread_t tid) +{ + _pthread_data_t *ptd; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)tid->user_data; + RT_ASSERT(ptd != RT_NULL); + + /* clear cleanup function */ + tid->cleanup = RT_NULL; + if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) + { + rt_sem_release(ptd->joinable_sem); + } + else + { + /* release pthread resource */ + _pthread_destroy(ptd); + } +} + +static void pthread_entry_stub(void *parameter) +{ + void *value; + _pthread_data_t *ptd; + + ptd = (_pthread_data_t *)parameter; + + /* execute pthread entry */ + value = ptd->thread_entry(ptd->thread_parameter); + /* set value */ + ptd->return_value = value; +} + +int pthread_create(pthread_t *pid, + const pthread_attr_t *attr, + void *(*start)(void *), void *parameter) +{ + int ret = 0; + void *stack; + char name[RT_NAME_MAX]; + static rt_uint16_t pthread_number = 0; + + pthread_t pth_id; + _pthread_data_t *ptd; + + /* pid shall be provided */ + RT_ASSERT(pid != RT_NULL); + + /* allocate posix thread data */ + pth_id = _pthread_data_create(); + if (pth_id == PTHREAD_NUM_MAX) + { + ret = ENOMEM; + goto __exit; + } + /* get pthread data */ + ptd = _pthread_get_data(pth_id); + + RT_ASSERT(ptd != RT_NULL); + + if (attr != RT_NULL) + { + ptd->attr = *attr; + } + else + { + /* use default attribute */ + pthread_attr_init(&ptd->attr); + } + + if (ptd->attr.stacksize == 0) + { + ret = EINVAL; + goto __exit; + } + + rt_snprintf(name, sizeof(name), "pth%02d", pthread_number ++); + + /* pthread is a static thread object */ + ptd->tid = (rt_thread_t) rt_malloc(sizeof(struct rt_thread)); + if (ptd->tid == RT_NULL) + { + ret = ENOMEM; + goto __exit; + } + memset(ptd->tid, 0, sizeof(struct rt_thread)); + + if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) + { + ptd->joinable_sem = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO); + if (ptd->joinable_sem == RT_NULL) + { + ret = ENOMEM; + goto __exit; + } + } + else + { + ptd->joinable_sem = RT_NULL; + } + + /* set parameter */ + ptd->thread_entry = start; + ptd->thread_parameter = parameter; + + /* stack */ + if (ptd->attr.stackaddr == 0) + { + stack = (void *)rt_malloc(ptd->attr.stacksize); + } + else + { + stack = (void *)(ptd->attr.stackaddr); + } + + if (stack == RT_NULL) + { + ret = ENOMEM; + goto __exit; + } + + /* initial this pthread to system */ + if (rt_thread_init(ptd->tid, name, pthread_entry_stub, ptd, + stack, ptd->attr.stacksize, + ptd->attr.schedparam.sched_priority, 20) != RT_EOK) + { + ret = EINVAL; + goto __exit; + } + + /* set pthread id */ + *pid = pth_id; + + /* set pthread cleanup function and ptd data */ + ptd->tid->cleanup = _pthread_cleanup; + ptd->tid->user_data = (rt_ubase_t)ptd; + + /* start thread */ + if (rt_thread_startup(ptd->tid) == RT_EOK) + return 0; + + /* start thread failed */ + rt_thread_detach(ptd->tid); + ret = EINVAL; + +__exit: + if (pth_id != PTHREAD_NUM_MAX) + _pthread_data_destroy(pth_id); + return ret; +} +RTM_EXPORT(pthread_create); + +int pthread_detach(pthread_t thread) +{ + int ret = 0; + _pthread_data_t *ptd = _pthread_get_data(thread); + if (ptd == RT_NULL) + { + /* invalid pthread id */ + ret = EINVAL; + goto __exit; + } + + rt_enter_critical(); + if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED) + { + /* The implementation has detected that the value specified by thread does not refer + * to a joinable thread. + */ + ret = EINVAL; + goto __exit; + } + + if ((ptd->tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) + { + /* this defunct pthread is not handled by idle */ + if (rt_sem_trytake(ptd->joinable_sem) != RT_EOK) + { + rt_sem_release(ptd->joinable_sem); + + /* change to detach state */ + ptd->attr.detachstate = PTHREAD_CREATE_DETACHED; + + /* detach joinable semaphore */ + if (ptd->joinable_sem) + { + rt_sem_delete(ptd->joinable_sem); + ptd->joinable_sem = RT_NULL; + } + } + else + { + /* destroy this pthread */ + _pthread_destroy(ptd); + } + + goto __exit; + } + else + { + /* change to detach state */ + ptd->attr.detachstate = PTHREAD_CREATE_DETACHED; + + /* detach joinable semaphore */ + if (ptd->joinable_sem) + { + rt_sem_delete(ptd->joinable_sem); + ptd->joinable_sem = RT_NULL; + } + } + +__exit: + rt_exit_critical(); + return ret; +} +RTM_EXPORT(pthread_detach); + +int pthread_join(pthread_t thread, void **value_ptr) +{ + _pthread_data_t *ptd; + rt_err_t result; + + ptd = _pthread_get_data(thread); + + if (ptd == RT_NULL) + { + return EINVAL; /* invalid pthread id */ + } + + if (ptd && ptd->tid == rt_thread_self()) + { + /* join self */ + return EDEADLK; + } + + if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED) + { + return EINVAL; /* join on a detached pthread */ + } + + result = rt_sem_take(ptd->joinable_sem, RT_WAITING_FOREVER); + if (result == RT_EOK) + { + /* get return value */ + if (value_ptr != RT_NULL) + *value_ptr = ptd->return_value; + + /* destroy this pthread */ + _pthread_destroy(ptd); + } + else + { + return ESRCH; + } + + return 0; +} +RTM_EXPORT(pthread_join); + +pthread_t pthread_self (void) +{ + rt_thread_t tid; + _pthread_data_t *ptd; + + tid = rt_thread_self(); + if (tid == NULL) return PTHREAD_NUM_MAX; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + RT_ASSERT(ptd != RT_NULL); + + return _pthread_data_get_pth(ptd); +} +RTM_EXPORT(pthread_self); + +void pthread_exit(void *value) +{ + _pthread_data_t *ptd; + _pthread_cleanup_t *cleanup; + extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; + + if (rt_thread_self() == NULL) return; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + + rt_enter_critical(); + /* disable cancel */ + ptd->cancelstate = PTHREAD_CANCEL_DISABLE; + /* set return value */ + ptd->return_value = value; + rt_exit_critical(); + + /* invoke pushed cleanup */ + while (ptd->cleanup != RT_NULL) + { + cleanup = ptd->cleanup; + ptd->cleanup = cleanup->next; + + cleanup->cleanup_func(cleanup->parameter); + /* release this cleanup function */ + rt_free(cleanup); + } + + /* destruct thread local key */ + if (ptd->tls != RT_NULL) + { + void *data; + rt_uint32_t index; + + for (index = 0; index < PTHREAD_KEY_MAX; index ++) + { + if (_thread_keys[index].is_used) + { + data = ptd->tls[index]; + if (data && _thread_keys[index].destructor) + _thread_keys[index].destructor(data); + } + } + + /* release tls area */ + rt_free(ptd->tls); + ptd->tls = RT_NULL; + } + + /* detach thread */ + rt_thread_detach(ptd->tid); + /* reschedule thread */ + rt_schedule(); +} +RTM_EXPORT(pthread_exit); + +int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + RT_ASSERT(once_control != RT_NULL); + RT_ASSERT(init_routine != RT_NULL); + + rt_enter_critical(); + if (!(*once_control)) + { + /* call routine once */ + *once_control = 1; + rt_exit_critical(); + + init_routine(); + } + rt_exit_critical(); + + return 0; +} +RTM_EXPORT(pthread_once); + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_atfork); + +int pthread_kill(pthread_t thread, int sig) +{ +#ifdef RT_USING_SIGNALS + _pthread_data_t *ptd; + int ret; + + ptd = _pthread_get_data(thread); + if (ptd) + { + ret = rt_thread_kill(ptd->tid, sig); + if (ret == -RT_EINVAL) + { + return EINVAL; + } + + return ret; + } + + return ESRCH; +#else + return ENOSYS; +#endif +} +RTM_EXPORT(pthread_kill); + +#ifdef RT_USING_SIGNALS +int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + return sigprocmask(how, set, oset); +} +#endif + +void pthread_cleanup_pop(int execute) +{ + _pthread_data_t *ptd; + _pthread_cleanup_t *cleanup; + + if (rt_thread_self() == NULL) return; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + RT_ASSERT(ptd != RT_NULL); + + if (execute) + { + rt_enter_critical(); + cleanup = ptd->cleanup; + if (cleanup) + ptd->cleanup = cleanup->next; + rt_exit_critical(); + + if (cleanup) + { + cleanup->cleanup_func(cleanup->parameter); + + rt_free(cleanup); + } + } +} +RTM_EXPORT(pthread_cleanup_pop); + +void pthread_cleanup_push(void (*routine)(void *), void *arg) +{ + _pthread_data_t *ptd; + _pthread_cleanup_t *cleanup; + + if (rt_thread_self() == NULL) return; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + RT_ASSERT(ptd != RT_NULL); + + cleanup = (_pthread_cleanup_t *)rt_malloc(sizeof(_pthread_cleanup_t)); + if (cleanup != RT_NULL) + { + cleanup->cleanup_func = routine; + cleanup->parameter = arg; + + rt_enter_critical(); + cleanup->next = ptd->cleanup; + ptd->cleanup = cleanup; + rt_exit_critical(); + } +} +RTM_EXPORT(pthread_cleanup_push); + +/* + * According to IEEE Std 1003.1, 2004 Edition , following pthreads + * interface support cancellation point: + * mq_receive() + * mq_send() + * mq_timedreceive() + * mq_timedsend() + * msgrcv() + * msgsnd() + * msync() + * pthread_cond_timedwait() + * pthread_cond_wait() + * pthread_join() + * pthread_testcancel() + * sem_timedwait() + * sem_wait() + * + * A cancellation point may also occur when a thread is + * executing the following functions: + * pthread_rwlock_rdlock() + * pthread_rwlock_timedrdlock() + * pthread_rwlock_timedwrlock() + * pthread_rwlock_wrlock() + * + * The pthread_cancel(), pthread_setcancelstate(), and pthread_setcanceltype() + * functions are defined to be async-cancel safe. + */ + +int pthread_setcancelstate(int state, int *oldstate) +{ + _pthread_data_t *ptd; + + if (rt_thread_self() == NULL) return EINVAL; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + RT_ASSERT(ptd != RT_NULL); + + if ((state == PTHREAD_CANCEL_ENABLE) || (state == PTHREAD_CANCEL_DISABLE)) + { + if (oldstate) + *oldstate = ptd->cancelstate; + ptd->cancelstate = state; + + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_setcancelstate); + +int pthread_setcanceltype(int type, int *oldtype) +{ + _pthread_data_t *ptd; + + if (rt_thread_self() == NULL) return EINVAL; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + RT_ASSERT(ptd != RT_NULL); + + if ((type != PTHREAD_CANCEL_DEFERRED) && (type != PTHREAD_CANCEL_ASYNCHRONOUS)) + return EINVAL; + + if (oldtype) + *oldtype = ptd->canceltype; + ptd->canceltype = type; + + return 0; +} +RTM_EXPORT(pthread_setcanceltype); + +void pthread_testcancel(void) +{ + int cancel = 0; + _pthread_data_t *ptd; + + if (rt_thread_self() == NULL) return; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + RT_ASSERT(ptd != RT_NULL); + + if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE) + cancel = ptd->canceled; + if (cancel) + pthread_exit((void *)PTHREAD_CANCELED); +} +RTM_EXPORT(pthread_testcancel); + +int pthread_cancel(pthread_t thread) +{ + _pthread_data_t *ptd; + + /* get posix thread data */ + ptd = _pthread_get_data(thread); + if (ptd == RT_NULL) + { + return EINVAL; + } + + /* cancel self */ + if (ptd->tid == rt_thread_self()) + return 0; + + /* set canceled */ + if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE) + { + ptd->canceled = 1; + if (ptd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + { + /* + * to detach thread. + * this thread will be removed from scheduler list + * and because there is a cleanup function in the + * thread (pthread_cleanup), it will move to defunct + * thread list and wait for handling in idle thread. + */ + rt_thread_detach(ptd->tid); + } + } + + return 0; +} +RTM_EXPORT(pthread_cancel); + diff --git a/components/libc/posix/pthreads/pthread.h b/components/libc/posix/pthreads/pthread.h new file mode 100644 index 0000000000..177b2539c5 --- /dev/null +++ b/components/libc/posix/pthreads/pthread.h @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#ifndef __PTHREAD_H__ +#define __PTHREAD_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define PTHREAD_KEY_MAX 8 + +#define PTHREAD_COND_INITIALIZER {-1, 0} +#define PTHREAD_RWLOCK_INITIALIZER {-1, 0} +#define PTHREAD_MUTEX_INITIALIZER {-1, 0} + +#define PTHREAD_CREATE_JOINABLE 0x00 +#define PTHREAD_CREATE_DETACHED 0x01 + +#define PTHREAD_EXPLICIT_SCHED 0 +#define PTHREAD_INHERIT_SCHED 1 + +typedef long pthread_t; +typedef long pthread_condattr_t; +typedef long pthread_rwlockattr_t; +typedef long pthread_mutexattr_t; +typedef long pthread_barrierattr_t; + +typedef int pthread_key_t; +typedef int pthread_once_t; + +enum +{ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_ENABLE, + PTHREAD_CANCEL_DEFERRED, + PTHREAD_CANCEL_DISABLE, + PTHREAD_CANCELED +}; + +enum +{ + PTHREAD_MUTEX_NORMAL = 0, + PTHREAD_MUTEX_RECURSIVE = 1, + PTHREAD_MUTEX_ERRORCHECK = 2, + PTHREAD_MUTEX_ERRORCHECK_NP = PTHREAD_MUTEX_ERRORCHECK, + PTHREAD_MUTEX_RECURSIVE_NP = PTHREAD_MUTEX_RECURSIVE, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + +/* init value for pthread_once_t */ +#define PTHREAD_ONCE_INIT 0 + +enum +{ + PTHREAD_PRIO_INHERIT =0, + PTHREAD_PRIO_NONE, + PTHREAD_PRIO_PROTECT, +}; + +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_SHARED 1 + +#define PTHREAD_SCOPE_PROCESS 0 +#define PTHREAD_SCOPE_SYSTEM 1 + +struct sched_param +{ + int sched_priority; +}; + +struct pthread_attr +{ + void* stackaddr; /* stack address of thread */ + int stacksize; /* stack size of thread */ + + int inheritsched; /* Inherit parent prio/policy */ + int schedpolicy; /* scheduler policy */ + struct sched_param schedparam; /* sched parameter */ + + int detachstate; /* detach state */ +}; +typedef struct pthread_attr pthread_attr_t; + +struct pthread_mutex +{ + pthread_mutexattr_t attr; + struct rt_mutex lock; +}; +typedef struct pthread_mutex pthread_mutex_t; + +struct pthread_cond +{ + pthread_condattr_t attr; + struct rt_semaphore sem; +}; +typedef struct pthread_cond pthread_cond_t; + +struct pthread_rwlock +{ + pthread_rwlockattr_t attr; + + pthread_mutex_t rw_mutex; /* basic lock on this struct */ + pthread_cond_t rw_condreaders; /* for reader threads waiting */ + pthread_cond_t rw_condwriters; /* for writer threads waiting */ + + int rw_nwaitreaders; /* the number of reader threads waiting */ + int rw_nwaitwriters; /* the number of writer threads waiting */ + int rw_refcount; /* 0: unlocked, -1: locked by writer, > 0 locked by n readers */ +}; +typedef struct pthread_rwlock pthread_rwlock_t; + +/* spinlock implementation, (ADVANCED REALTIME THREADS)*/ +struct pthread_spinlock +{ + int lock; +}; +typedef struct pthread_spinlock pthread_spinlock_t; + +struct pthread_barrier +{ + int count; + pthread_cond_t cond; + pthread_mutex_t mutex; +}; +typedef struct pthread_barrier pthread_barrier_t; + +/* pthread thread interface */ +int pthread_attr_destroy(pthread_attr_t *attr); +int pthread_attr_init(pthread_attr_t *attr); +int pthread_attr_setdetachstate(pthread_attr_t *attr, int state); +int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state); +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); +int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy); +int pthread_attr_setschedparam(pthread_attr_t *attr,struct sched_param const *param); +int pthread_attr_getschedparam(pthread_attr_t const *attr,struct sched_param *param); +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size); +int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size); +int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr); +int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr); +int pthread_attr_setstack(pthread_attr_t *attr, + void *stack_base, + size_t stack_size); +int pthread_attr_getstack(pthread_attr_t const *attr, + void **stack_base, + size_t *stack_size); +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard_size); +int pthread_attr_getguardsize(pthread_attr_t const *attr, size_t *guard_size); +int pthread_attr_setscope(pthread_attr_t *attr, int scope); +int pthread_attr_getscope(pthread_attr_t const *attr); +int pthread_system_init(void); +int pthread_create (pthread_t *tid, const pthread_attr_t *attr, + void *(*start) (void *), void *arg); + +int pthread_detach (pthread_t thread); +int pthread_join (pthread_t thread, void **value_ptr); + +rt_inline int pthread_equal (pthread_t t1, pthread_t t2) +{ + return t1 == t2; +} + +pthread_t pthread_self (void); + +void pthread_exit (void *value_ptr); +int pthread_once(pthread_once_t * once_control, void (*init_routine) (void)); + +/* pthread cleanup */ +void pthread_cleanup_pop(int execute); +void pthread_cleanup_push(void (*routine)(void*), void *arg); + +/* pthread cancel */ +int pthread_cancel(pthread_t thread); +void pthread_testcancel(void); +int pthread_setcancelstate(int state, int *oldstate); +int pthread_setcanceltype(int type, int *oldtype); + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); +int pthread_kill(pthread_t thread, int sig); + +/* pthread mutex interface */ +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); +int pthread_mutex_destroy(pthread_mutex_t *mutex); +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_init(pthread_mutexattr_t *attr); +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type); +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); +int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared); + +/* pthread condition interface */ +int pthread_condattr_destroy(pthread_condattr_t *attr); +int pthread_condattr_init(pthread_condattr_t *attr); + +/* ADVANCED REALTIME feature in IEEE Std 1003.1, 2004 Edition */ +int pthread_condattr_getclock(const pthread_condattr_t *attr, + clockid_t *clock_id); +int pthread_condattr_setclock(pthread_condattr_t *attr, + clockid_t clock_id); + +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); +int pthread_cond_destroy(pthread_cond_t *cond); +int pthread_cond_broadcast(pthread_cond_t *cond); +int pthread_cond_signal(pthread_cond_t *cond); + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); + +/* pthread rwlock interface */ +int pthread_rwlockattr_init (pthread_rwlockattr_t *attr); +int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr); +int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared); +int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); + +int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); +int pthread_rwlock_destroy (pthread_rwlock_t *rwlock); + +int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); +int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); + +int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, const struct timespec *abstime); +int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, const struct timespec *abstime); + +int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); + +int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); +int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); + +/* pthread spinlock interface */ +int pthread_spin_init (pthread_spinlock_t *lock, int pshared); +int pthread_spin_destroy (pthread_spinlock_t *lock); + +int pthread_spin_lock (pthread_spinlock_t * lock); +int pthread_spin_trylock (pthread_spinlock_t * lock); +int pthread_spin_unlock (pthread_spinlock_t * lock); + +/* pthread barrier interface */ +int pthread_barrierattr_destroy(pthread_barrierattr_t *attr); +int pthread_barrierattr_init(pthread_barrierattr_t *attr); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared); + +int pthread_barrier_destroy(pthread_barrier_t *barrier); +int pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned count); + +int pthread_barrier_wait(pthread_barrier_t *barrier); + +int pthread_setspecific(pthread_key_t key, const void *value); +void *pthread_getspecific(pthread_key_t key); +int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); +int pthread_key_delete(pthread_key_t key); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/libc/posix/pthreads/pthread_attr.c b/components/libc/posix/pthreads/pthread_attr.c new file mode 100644 index 0000000000..4aedf5a90d --- /dev/null +++ b/components/libc/posix/pthreads/pthread_attr.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#include +#include "pthread.h" +#include "sched.h" +#include + +#define DEFAULT_STACK_SIZE 2048 +#define DEFAULT_PRIORITY (RT_THREAD_PRIORITY_MAX/2 + RT_THREAD_PRIORITY_MAX/4) + +const pthread_attr_t pthread_default_attr = +{ + 0, /* stack base */ + DEFAULT_STACK_SIZE, /* stack size */ + + PTHREAD_INHERIT_SCHED, /* Inherit parent prio/policy */ + SCHED_FIFO, /* scheduler policy */ + { + DEFAULT_PRIORITY, /* scheduler priority */ + }, + PTHREAD_CREATE_JOINABLE, /* detach state */ +}; + +int pthread_attr_init(pthread_attr_t *attr) +{ + RT_ASSERT(attr != RT_NULL); + + *attr = pthread_default_attr; + + return 0; +} +RTM_EXPORT(pthread_attr_init); + +int pthread_attr_destroy(pthread_attr_t *attr) +{ + RT_ASSERT(attr != RT_NULL); + + memset(attr, 0, sizeof(pthread_attr_t)); + + return 0; +} +RTM_EXPORT(pthread_attr_destroy); + +int pthread_attr_setdetachstate(pthread_attr_t *attr, int state) +{ + RT_ASSERT(attr != RT_NULL); + + if (state != PTHREAD_CREATE_JOINABLE && state != PTHREAD_CREATE_DETACHED) + return EINVAL; + + attr->detachstate = state; + + return 0; +} +RTM_EXPORT(pthread_attr_setdetachstate); + +int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state) +{ + RT_ASSERT(attr != RT_NULL); + + *state = (int)attr->detachstate; + + return 0; +} +RTM_EXPORT(pthread_attr_getdetachstate); + +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) +{ + RT_ASSERT(attr != RT_NULL); + + attr->schedpolicy = policy; + + return 0; +} +RTM_EXPORT(pthread_attr_setschedpolicy); + +int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy) +{ + RT_ASSERT(attr != RT_NULL); + + *policy = (int)attr->schedpolicy; + + return 0; +} +RTM_EXPORT(pthread_attr_getschedpolicy); + +int pthread_attr_setschedparam(pthread_attr_t *attr, + struct sched_param const *param) +{ + RT_ASSERT(attr != RT_NULL); + RT_ASSERT(param != RT_NULL); + + attr->schedparam.sched_priority = param->sched_priority; + + return 0; +} +RTM_EXPORT(pthread_attr_setschedparam); + +int pthread_attr_getschedparam(pthread_attr_t const *attr, + struct sched_param *param) +{ + RT_ASSERT(attr != RT_NULL); + RT_ASSERT(param != RT_NULL); + + param->sched_priority = attr->schedparam.sched_priority; + + return 0; +} +RTM_EXPORT(pthread_attr_getschedparam); + +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + attr->stacksize = stack_size; + + return 0; +} +RTM_EXPORT(pthread_attr_setstacksize); + +int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + *stack_size = attr->stacksize; + + return 0; +} +RTM_EXPORT(pthread_attr_getstacksize); + +int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr) +{ + RT_ASSERT(attr != RT_NULL); + + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_attr_setstackaddr); + +int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr) +{ + RT_ASSERT(attr != RT_NULL); + + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_attr_getstackaddr); + +int pthread_attr_setstack(pthread_attr_t *attr, + void *stack_base, + size_t stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + attr->stackaddr = stack_base; + attr->stacksize = RT_ALIGN_DOWN(stack_size, RT_ALIGN_SIZE); + + return 0; +} +RTM_EXPORT(pthread_attr_setstack); + +int pthread_attr_getstack(pthread_attr_t const *attr, + void **stack_base, + size_t *stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + *stack_base = attr->stackaddr; + *stack_size = attr->stacksize; + + return 0; +} +RTM_EXPORT(pthread_attr_getstack); + +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard_size) +{ + return EOPNOTSUPP; +} + +int pthread_attr_getguardsize(pthread_attr_t const *attr, size_t *guard_size) +{ + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_attr_getguardsize); + +int pthread_attr_setscope(pthread_attr_t *attr, int scope) +{ + if (scope == PTHREAD_SCOPE_SYSTEM) + return 0; + if (scope == PTHREAD_SCOPE_PROCESS) + return EOPNOTSUPP; + + return EINVAL; +} +RTM_EXPORT(pthread_attr_setscope); + +int pthread_attr_getscope(pthread_attr_t const *attr) +{ + return PTHREAD_SCOPE_SYSTEM; +} +RTM_EXPORT(pthread_attr_getscope); diff --git a/components/libc/posix/pthreads/pthread_barrier.c b/components/libc/posix/pthreads/pthread_barrier.c new file mode 100644 index 0000000000..1a5b7fa3f9 --- /dev/null +++ b/components/libc/posix/pthreads/pthread_barrier.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#include + +int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + if (!attr) + return EINVAL; + + return 0; +} +RTM_EXPORT(pthread_barrierattr_destroy); + +int pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + if (!attr) + return EINVAL; + *attr = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_barrierattr_init); + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, + int *pshared) +{ + if (!attr) + return EINVAL; + *pshared = (int)*attr; + + return 0; +} +RTM_EXPORT(pthread_barrierattr_getpshared); + +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + if (!attr) + return EINVAL; + if (pshared == PTHREAD_PROCESS_PRIVATE) + attr = PTHREAD_PROCESS_PRIVATE; + + return EINVAL; +} +RTM_EXPORT(pthread_barrierattr_setpshared); + +int pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + rt_err_t result; + + if (!barrier) + return EINVAL; + + result = pthread_cond_destroy(&(barrier->cond)); + + return result; +} +RTM_EXPORT(pthread_barrier_destroy); + +int pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned count) +{ + if (!barrier) + return EINVAL; + if (attr && (*attr != PTHREAD_PROCESS_PRIVATE)) + return EINVAL; + + barrier->count = count; + pthread_cond_init(&(barrier->cond), NULL); + pthread_mutex_init(&(barrier->mutex), NULL); + + return 0; +} +RTM_EXPORT(pthread_barrier_init); + +int pthread_barrier_wait(pthread_barrier_t *barrier) +{ + rt_err_t result; + if (!barrier) + return EINVAL; + + result = pthread_mutex_lock(&(barrier->mutex)); + if (result != 0) + return EINVAL; + + if (barrier->count == 0) + result = EINVAL; + else + { + barrier->count -= 1; + if (barrier->count == 0) /* broadcast condition */ + pthread_cond_broadcast(&(barrier->cond)); + else + pthread_cond_wait(&(barrier->cond), &(barrier->mutex)); + } + + pthread_mutex_unlock(&(barrier->mutex)); + + return result; +} +RTM_EXPORT(pthread_barrier_wait); + diff --git a/components/libc/posix/pthreads/pthread_cond.c b/components/libc/posix/pthreads/pthread_cond.c new file mode 100644 index 0000000000..9bf49704ed --- /dev/null +++ b/components/libc/posix/pthreads/pthread_cond.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#include +#include "pthread_internal.h" + +int pthread_condattr_destroy(pthread_condattr_t *attr) +{ + if (!attr) + return EINVAL; + + return 0; +} +RTM_EXPORT(pthread_condattr_destroy); + +int pthread_condattr_init(pthread_condattr_t *attr) +{ + if (!attr) + return EINVAL; + *attr = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_condattr_init); + +int pthread_condattr_getclock(const pthread_condattr_t *attr, + clockid_t *clock_id) +{ + return 0; +} +RTM_EXPORT(pthread_condattr_getclock); + +int pthread_condattr_setclock(pthread_condattr_t *attr, + clockid_t clock_id) +{ + return 0; +} +RTM_EXPORT(pthread_condattr_setclock); + +int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared) +{ + if (!attr || !pshared) + return EINVAL; + + *pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_condattr_getpshared); + +int pthread_condattr_setpshared(pthread_condattr_t*attr, int pshared) +{ + if ((pshared != PTHREAD_PROCESS_PRIVATE) && + (pshared != PTHREAD_PROCESS_SHARED)) + { + return EINVAL; + } + + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; + + return 0; +} +RTM_EXPORT(pthread_condattr_setpshared); + +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + rt_err_t result; + char cond_name[RT_NAME_MAX]; + static rt_uint16_t cond_num = 0; + + /* parameter check */ + if (cond == RT_NULL) + return EINVAL; + if ((attr != RT_NULL) && (*attr != PTHREAD_PROCESS_PRIVATE)) + return EINVAL; + + rt_snprintf(cond_name, sizeof(cond_name), "cond%02d", cond_num++); + + if (attr == RT_NULL) /* use default value */ + cond->attr = PTHREAD_PROCESS_PRIVATE; + else + cond->attr = *attr; + + result = rt_sem_init(&cond->sem, cond_name, 0, RT_IPC_FLAG_FIFO); + if (result != RT_EOK) + return EINVAL; + + /* detach the object from system object container */ + rt_object_detach(&(cond->sem.parent.parent)); + cond->sem.parent.parent.type = RT_Object_Class_Semaphore; + + return 0; +} +RTM_EXPORT(pthread_cond_init); + +int pthread_cond_destroy(pthread_cond_t *cond) +{ + rt_err_t result; + if (cond == RT_NULL) + return EINVAL; + if (cond->attr == -1) + return 0; /* which is not initialized */ + + result = rt_sem_trytake(&(cond->sem)); + if (result != RT_EOK) + return EBUSY; + + /* clean condition */ + rt_memset(cond, 0, sizeof(pthread_cond_t)); + cond->attr = -1; + + return 0; +} +RTM_EXPORT(pthread_cond_destroy); + +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + rt_err_t result; + + if (cond == RT_NULL) + return EINVAL; + if (cond->attr == -1) + pthread_cond_init(cond, RT_NULL); + + rt_enter_critical(); + while (1) + { + /* try to take condition semaphore */ + result = rt_sem_trytake(&(cond->sem)); + if (result == -RT_ETIMEOUT) + { + /* it's timeout, release this semaphore */ + rt_sem_release(&(cond->sem)); + } + else if (result == RT_EOK) + { + /* has taken this semaphore, release it */ + rt_sem_release(&(cond->sem)); + break; + } + else + { + rt_exit_critical(); + + return EINVAL; + } + } + rt_exit_critical(); + + return 0; +} +RTM_EXPORT(pthread_cond_broadcast); + +int pthread_cond_signal(pthread_cond_t *cond) +{ + rt_err_t result; + + if (cond == RT_NULL) + return EINVAL; + if (cond->attr == -1) + pthread_cond_init(cond, RT_NULL); + + result = rt_sem_release(&(cond->sem)); + if (result == RT_EOK) + return 0; + + return 0; +} +RTM_EXPORT(pthread_cond_signal); + +rt_err_t _pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + rt_int32_t timeout) +{ + rt_err_t result; + + if (!cond || !mutex) + return -RT_ERROR; + /* check whether initialized */ + if (cond->attr == -1) + pthread_cond_init(cond, RT_NULL); + + /* The mutex was not owned by the current thread at the time of the call. */ + if (mutex->lock.owner != rt_thread_self()) + return -RT_ERROR; + /* unlock a mutex failed */ + if (pthread_mutex_unlock(mutex) != 0) + return -RT_ERROR; + + result = rt_sem_take(&(cond->sem), timeout); + /* lock mutex again */ + pthread_mutex_lock(mutex); + + return result; +} +RTM_EXPORT(_pthread_cond_timedwait); + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + rt_err_t result; + + result = _pthread_cond_timedwait(cond, mutex, RT_WAITING_FOREVER); + if (result == RT_EOK) + return 0; + + return EINVAL; +} +RTM_EXPORT(pthread_cond_wait); + +int pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + int timeout; + rt_err_t result; + + timeout = rt_timespec_to_tick(abstime); + result = _pthread_cond_timedwait(cond, mutex, timeout); + if (result == RT_EOK) + return 0; + if (result == -RT_ETIMEOUT) + return ETIMEDOUT; + + return EINVAL; +} +RTM_EXPORT(pthread_cond_timedwait); + diff --git a/components/libc/posix/pthreads/pthread_internal.h b/components/libc/posix/pthreads/pthread_internal.h new file mode 100644 index 0000000000..1fce29f636 --- /dev/null +++ b/components/libc/posix/pthreads/pthread_internal.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#ifndef __PTHREAD_INTERNAL_H__ +#define __PTHREAD_INTERNAL_H__ + +#include +#include +#include + +struct _pthread_cleanup +{ + void (*cleanup_func)(void *parameter); + void *parameter; + + struct _pthread_cleanup *next; +}; +typedef struct _pthread_cleanup _pthread_cleanup_t; + +struct _pthread_key_data +{ + int is_used; + void (*destructor)(void *parameter); +}; +typedef struct _pthread_key_data _pthread_key_data_t; + +#ifndef PTHREAD_NUM_MAX +#define PTHREAD_NUM_MAX 32 +#endif + +#define PTHREAD_MAGIC 0x70746873 +struct _pthread_data +{ + rt_uint32_t magic; + pthread_attr_t attr; + rt_thread_t tid; + + void* (*thread_entry)(void *parameter); + void *thread_parameter; + + /* return value */ + void *return_value; + + /* semaphore for joinable thread */ + rt_sem_t joinable_sem; + + /* cancel state and type */ + rt_uint8_t cancelstate; + volatile rt_uint8_t canceltype; + volatile rt_uint8_t canceled; + + _pthread_cleanup_t *cleanup; + void** tls; /* thread-local storage area */ +}; +typedef struct _pthread_data _pthread_data_t; + +_pthread_data_t *_pthread_get_data(pthread_t thread); + +void posix_mq_system_init(void); +void posix_sem_system_init(void); +void pthread_key_system_init(void); + +#endif diff --git a/components/libc/posix/pthreads/pthread_mutex.c b/components/libc/posix/pthreads/pthread_mutex.c new file mode 100644 index 0000000000..a681380b11 --- /dev/null +++ b/components/libc/posix/pthreads/pthread_mutex.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#include +#include "pthread.h" + +#define MUTEXATTR_SHARED_MASK 0x0010 +#define MUTEXATTR_TYPE_MASK 0x000f + +const pthread_mutexattr_t pthread_default_mutexattr = PTHREAD_PROCESS_PRIVATE; + +int pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + if (attr) + { + *attr = pthread_default_mutexattr; + + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_init); + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + if (attr) + { + *attr = -1; + + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_destroy); + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) +{ + if (attr && type) + { + int atype = (*attr & MUTEXATTR_TYPE_MASK); + + if (atype >= PTHREAD_MUTEX_NORMAL && atype <= PTHREAD_MUTEX_ERRORCHECK) + { + *type = atype; + + return 0; + } + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_gettype); + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + if (attr && type >= PTHREAD_MUTEX_NORMAL && type <= PTHREAD_MUTEX_ERRORCHECK) + { + *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type; + + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_settype); + +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) +{ + if (!attr) + return EINVAL; + + switch (pshared) + { + case PTHREAD_PROCESS_PRIVATE: + *attr &= ~MUTEXATTR_SHARED_MASK; + return 0; + + case PTHREAD_PROCESS_SHARED: + *attr |= MUTEXATTR_SHARED_MASK; + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_setpshared); + +int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared) +{ + if (!attr || !pshared) + return EINVAL; + + *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED + : PTHREAD_PROCESS_PRIVATE; + return 0; +} +RTM_EXPORT(pthread_mutexattr_getpshared); + +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + rt_err_t result; + char name[RT_NAME_MAX]; + static rt_uint16_t pthread_mutex_number = 0; + + if (!mutex) + return EINVAL; + + /* build mutex name */ + rt_snprintf(name, sizeof(name), "pmtx%02d", pthread_mutex_number ++); + if (attr == RT_NULL) + mutex->attr = pthread_default_mutexattr; + else + mutex->attr = *attr; + + /* init mutex lock */ + result = rt_mutex_init(&(mutex->lock), name, RT_IPC_FLAG_FIFO); + if (result != RT_EOK) + return EINVAL; + + /* detach the object from system object container */ + rt_object_detach(&(mutex->lock.parent.parent)); + mutex->lock.parent.parent.type = RT_Object_Class_Mutex; + + return 0; +} +RTM_EXPORT(pthread_mutex_init); + +int pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + if (!mutex || mutex->attr == -1) + return EINVAL; + + /* it's busy */ + if (mutex->lock.owner != RT_NULL) + return EBUSY; + + rt_memset(mutex, 0, sizeof(pthread_mutex_t)); + mutex->attr = -1; + + return 0; +} +RTM_EXPORT(pthread_mutex_destroy); + +int pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int mtype; + rt_err_t result; + + if (!mutex) + return EINVAL; + + if (mutex->attr == -1) + { + /* init mutex */ + pthread_mutex_init(mutex, RT_NULL); + } + + mtype = mutex->attr & MUTEXATTR_TYPE_MASK; + rt_enter_critical(); + if (mutex->lock.owner == rt_thread_self() && + mtype != PTHREAD_MUTEX_RECURSIVE) + { + rt_exit_critical(); + + return EDEADLK; + } + rt_exit_critical(); + + result = rt_mutex_take(&(mutex->lock), RT_WAITING_FOREVER); + if (result == RT_EOK) + return 0; + + return EINVAL; +} +RTM_EXPORT(pthread_mutex_lock); + +int pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + rt_err_t result; + + if (!mutex) + return EINVAL; + if (mutex->attr == -1) + { + /* init mutex */ + pthread_mutex_init(mutex, RT_NULL); + } + + if (mutex->lock.owner != rt_thread_self()) + { + int mtype; + mtype = mutex->attr & MUTEXATTR_TYPE_MASK; + + /* error check, return EPERM */ + if (mtype == PTHREAD_MUTEX_ERRORCHECK) + return EPERM; + + /* no thread waiting on this mutex */ + if (mutex->lock.owner == RT_NULL) + return 0; + } + + result = rt_mutex_release(&(mutex->lock)); + if (result == RT_EOK) + return 0; + + return EINVAL; +} +RTM_EXPORT(pthread_mutex_unlock); + +int pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + rt_err_t result; + int mtype; + + if (!mutex) + return EINVAL; + if (mutex->attr == -1) + { + /* init mutex */ + pthread_mutex_init(mutex, RT_NULL); + } + + mtype = mutex->attr & MUTEXATTR_TYPE_MASK; + rt_enter_critical(); + if (mutex->lock.owner == rt_thread_self() && + mtype != PTHREAD_MUTEX_RECURSIVE) + { + rt_exit_critical(); + + return EDEADLK; + } + rt_exit_critical(); + + result = rt_mutex_take(&(mutex->lock), 0); + if (result == RT_EOK) return 0; + + return EBUSY; +} +RTM_EXPORT(pthread_mutex_trylock); diff --git a/components/libc/posix/pthreads/pthread_rwlock.c b/components/libc/posix/pthreads/pthread_rwlock.c new file mode 100644 index 0000000000..1c2fe19f5f --- /dev/null +++ b/components/libc/posix/pthreads/pthread_rwlock.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#include + +int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) +{ + if (!attr) + return EINVAL; + *attr = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_rwlockattr_init); + +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) +{ + if (!attr) + return EINVAL; + + return 0; +} +RTM_EXPORT(pthread_rwlockattr_destroy); + +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, + int *pshared) +{ + if (!attr || !pshared) + return EINVAL; + + *pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_rwlockattr_getpshared); + +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) +{ + if (!attr || pshared != PTHREAD_PROCESS_PRIVATE) + return EINVAL; + + return 0; +} +RTM_EXPORT(pthread_rwlockattr_setpshared); + +int pthread_rwlock_init(pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + if (!rwlock) + return EINVAL; + + rwlock->attr = PTHREAD_PROCESS_PRIVATE; + pthread_mutex_init(&(rwlock->rw_mutex), NULL); + pthread_cond_init(&(rwlock->rw_condreaders), NULL); + pthread_cond_init(&(rwlock->rw_condwriters), NULL); + + rwlock->rw_nwaitwriters = 0; + rwlock->rw_nwaitreaders = 0; + rwlock->rw_refcount = 0; + + return 0; +} +RTM_EXPORT(pthread_rwlock_init); + +int pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + return 0; /* rwlock is not initialized */ + + if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + if (rwlock->rw_refcount != 0 || + rwlock->rw_nwaitreaders != 0 || + rwlock->rw_nwaitwriters != 0) + { + result = EBUSY; + + return result; + } + else + { + /* check whether busy */ + result = rt_sem_trytake(&(rwlock->rw_condreaders.sem)); + if (result == RT_EOK) + { + result = rt_sem_trytake(&(rwlock->rw_condwriters.sem)); + if (result == RT_EOK) + { + rt_sem_release(&(rwlock->rw_condreaders.sem)); + rt_sem_release(&(rwlock->rw_condwriters.sem)); + + pthread_cond_destroy(&rwlock->rw_condreaders); + pthread_cond_destroy(&rwlock->rw_condwriters); + } + else + { + rt_sem_release(&(rwlock->rw_condreaders.sem)); + result = EBUSY; + } + } + else + result = EBUSY; + } + + pthread_mutex_unlock(&rwlock->rw_mutex); + if (result == 0) + pthread_mutex_destroy(&rwlock->rw_mutex); + + return result; +} +RTM_EXPORT(pthread_rwlock_destroy); + +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + /* give preference to waiting writers */ + while (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) + { + rwlock->rw_nwaitreaders++; + /* rw_mutex will be released when waiting for rw_condreaders */ + result = pthread_cond_wait(&rwlock->rw_condreaders, &rwlock->rw_mutex); + /* rw_mutex should have been taken again when returned from waiting */ + rwlock->rw_nwaitreaders--; + if (result != 0) /* wait error */ + break; + } + + /* another reader has a read lock */ + if (result == 0) + rwlock->rw_refcount++; + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return (result); +} +RTM_EXPORT(pthread_rwlock_rdlock); + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + if (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) + result = EBUSY; /* held by a writer or waiting writers */ + else + rwlock->rw_refcount++; /* increment count of reader locks */ + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_tryrdlock); + +int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + /* give preference to waiting writers */ + while (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) + { + rwlock->rw_nwaitreaders++; + /* rw_mutex will be released when waiting for rw_condreaders */ + result = pthread_cond_timedwait(&rwlock->rw_condreaders, &rwlock->rw_mutex, abstime); + /* rw_mutex should have been taken again when returned from waiting */ + rwlock->rw_nwaitreaders--; + if (result != 0) + break; + } + + /* another reader has a read lock */ + if (result == 0) + rwlock->rw_refcount++; + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return (result); +} +RTM_EXPORT(pthread_rwlock_timedrdlock); + +int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + while (rwlock->rw_refcount != 0) + { + rwlock->rw_nwaitwriters++; + /* rw_mutex will be released when waiting for rw_condwriters */ + result = pthread_cond_timedwait(&rwlock->rw_condwriters, &rwlock->rw_mutex, abstime); + /* rw_mutex should have been taken again when returned from waiting */ + rwlock->rw_nwaitwriters--; + + if (result != 0) + break; + } + + if (result == 0) + rwlock->rw_refcount = -1; + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_timedwrlock); + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + if (rwlock->rw_refcount != 0) + result = EBUSY; /* held by either writer or reader(s) */ + else + rwlock->rw_refcount = -1; /* available, indicate a writer has it */ + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_trywrlock); + +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + if (rwlock->rw_refcount > 0) + rwlock->rw_refcount--; /* releasing a reader */ + else if (rwlock->rw_refcount == -1) + rwlock->rw_refcount = 0; /* releasing a writer */ + + /* give preference to waiting writers over waiting readers */ + if (rwlock->rw_nwaitwriters > 0) + { + if (rwlock->rw_refcount == 0) + result = pthread_cond_signal(&rwlock->rw_condwriters); + } + else if (rwlock->rw_nwaitreaders > 0) + { + result = pthread_cond_broadcast(&rwlock->rw_condreaders); + } + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_unlock); + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + while (rwlock->rw_refcount != 0) + { + rwlock->rw_nwaitwriters++; + /* rw_mutex will be released when waiting for rw_condwriters */ + result = pthread_cond_wait(&rwlock->rw_condwriters, &rwlock->rw_mutex); + /* rw_mutex should have been taken again when returned from waiting */ + rwlock->rw_nwaitwriters--; + + if (result != 0) + break; + } + + if (result == 0) + rwlock->rw_refcount = -1; + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_wrlock); + diff --git a/components/libc/posix/pthreads/pthread_spin.c b/components/libc/posix/pthreads/pthread_spin.c new file mode 100644 index 0000000000..3f3dc1593c --- /dev/null +++ b/components/libc/posix/pthreads/pthread_spin.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#include + +int pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + if (!lock) + return EINVAL; + + lock->lock = 0; + + return 0; +} + +int pthread_spin_destroy (pthread_spinlock_t *lock) +{ + if (!lock) + return EINVAL; + + return 0; +} + +int pthread_spin_lock (pthread_spinlock_t *lock) +{ + if (!lock) + return EINVAL; + + while (!(lock->lock)) + { + lock->lock = 1; + } + + return 0; +} + +int pthread_spin_trylock (pthread_spinlock_t *lock) +{ + if (!lock) + return EINVAL; + + if (!(lock->lock)) + { + lock->lock = 1; + + return 0; + } + + return EBUSY; +} + +int pthread_spin_unlock (pthread_spinlock_t *lock) +{ + if (!lock) + return EINVAL; + if (!(lock->lock)) + return EPERM; + + lock->lock = 0; + + return 0; +} diff --git a/components/libc/posix/pthreads/pthread_tls.c b/components/libc/posix/pthreads/pthread_tls.c new file mode 100644 index 0000000000..d48df7f2dd --- /dev/null +++ b/components/libc/posix/pthreads/pthread_tls.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#include +#include "pthread_internal.h" + +_pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; + +void pthread_key_system_init() +{ + rt_memset(&_thread_keys[0], 0, sizeof(_thread_keys)); +} + +void *pthread_getspecific(pthread_key_t key) +{ + struct _pthread_data* ptd; + + if (rt_thread_self() == NULL) return NULL; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + RT_ASSERT(ptd != NULL); + + if (ptd->tls == NULL) + return NULL; + + if ((key < PTHREAD_KEY_MAX) && (_thread_keys[key].is_used)) + return ptd->tls[key]; + + return NULL; +} +RTM_EXPORT(pthread_getspecific); + +int pthread_setspecific(pthread_key_t key, const void *value) +{ + struct _pthread_data* ptd; + + if (rt_thread_self() == NULL) return EINVAL; + + /* get pthread data from user data of thread */ + ptd = (_pthread_data_t *)rt_thread_self()->user_data; + RT_ASSERT(ptd != NULL); + + /* check tls area */ + if (ptd->tls == NULL) + { + ptd->tls = (void**)rt_malloc(sizeof(void*) * PTHREAD_KEY_MAX); + } + + if ((key < PTHREAD_KEY_MAX) && _thread_keys[key].is_used) + { + ptd->tls[key] = (void *)value; + + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_setspecific); + +int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) +{ + rt_uint32_t index; + + rt_enter_critical(); + for (index = 0; index < PTHREAD_KEY_MAX; index ++) + { + if (_thread_keys[index].is_used == 0) + { + _thread_keys[index].is_used = 1; + _thread_keys[index].destructor = destructor; + + *key = index; + + rt_exit_critical(); + + return 0; + } + } + + rt_exit_critical(); + + return EAGAIN; +} +RTM_EXPORT(pthread_key_create); + +int pthread_key_delete(pthread_key_t key) +{ + if (key >= PTHREAD_KEY_MAX) + return EINVAL; + + rt_enter_critical(); + _thread_keys[key].is_used = 0; + _thread_keys[key].destructor = 0; + rt_exit_critical(); + + return 0; +} +RTM_EXPORT(pthread_key_delete); + diff --git a/components/libc/posix/pthreads/sched.c b/components/libc/posix/pthreads/sched.c new file mode 100644 index 0000000000..5f2a53c01f --- /dev/null +++ b/components/libc/posix/pthreads/sched.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include + +int sched_yield(void) +{ + rt_thread_yield(); + + return 0; +} +RTM_EXPORT(sched_yield); + +int sched_get_priority_min(int policy) +{ + if (policy != SCHED_FIFO && policy != SCHED_RR) + return EINVAL; + + return 0; +} +RTM_EXPORT(sched_get_priority_min); + +int sched_get_priority_max(int policy) +{ + if (policy != SCHED_FIFO && policy != SCHED_RR) + return EINVAL; + + return RT_THREAD_PRIORITY_MAX - 1; +} +RTM_EXPORT(sched_get_priority_max); + +int sched_setscheduler(pid_t pid, int policy) +{ + return EOPNOTSUPP; +} +RTM_EXPORT(sched_setscheduler); diff --git a/components/libc/posix/pthreads/sched.h b/components/libc/posix/pthreads/sched.h new file mode 100644 index 0000000000..07e2c0c6a8 --- /dev/null +++ b/components/libc/posix/pthreads/sched.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __SCHED_H__ +#define __SCHED_H__ + +#include +#include + +/* Thread scheduling policies */ +enum +{ + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +int sched_yield(void); +int sched_get_priority_min(int policy); +int sched_get_priority_max(int policy); +int sched_setscheduler(pid_t pid, int policy); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/libc/posix/pthreads/semaphore.c b/components/libc/posix/pthreads/semaphore.c new file mode 100644 index 0000000000..5e59ae850f --- /dev/null +++ b/components/libc/posix/pthreads/semaphore.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#include +#include +#include "semaphore.h" +#include "pthread_internal.h" + +static sem_t *posix_sem_list = RT_NULL; +static struct rt_semaphore posix_sem_lock; +void posix_sem_system_init() +{ + rt_sem_init(&posix_sem_lock, "psem", 1, RT_IPC_FLAG_FIFO); +} + +rt_inline void posix_sem_insert(sem_t *psem) +{ + psem->next = posix_sem_list; + posix_sem_list = psem; +} + +static void posix_sem_delete(sem_t *psem) +{ + sem_t *iter; + if (posix_sem_list == psem) + { + posix_sem_list = psem->next; + + rt_sem_delete(psem->sem); + rt_free(psem); + + return; + } + for (iter = posix_sem_list; iter->next != RT_NULL; iter = iter->next) + { + if (iter->next == psem) + { + /* delete this mq */ + if (psem->next != RT_NULL) + iter->next = psem->next; + else + iter->next = RT_NULL; + + /* delete RT-Thread mqueue */ + rt_sem_delete(psem->sem); + rt_free(psem); + + return ; + } + } +} + +static sem_t *posix_sem_find(const char* name) +{ + sem_t *iter; + rt_object_t object; + + for (iter = posix_sem_list; iter != RT_NULL; iter = iter->next) + { + object = (rt_object_t)iter->sem; + + if (strncmp(object->name, name, RT_NAME_MAX) == 0) + { + return iter; + } + } + + return RT_NULL; +} + +int sem_close(sem_t *sem) +{ + if (sem == RT_NULL) + { + rt_set_errno(EINVAL); + + return -1; + } + + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + sem->refcount --; + if (sem->refcount == 0) + { + /* delete from posix semaphore list */ + if (sem->unlinked) + posix_sem_delete(sem); + sem = RT_NULL; + } + rt_sem_release(&posix_sem_lock); + + return 0; +} +RTM_EXPORT(sem_close); + +int sem_destroy(sem_t *sem) +{ + rt_err_t result; + + if ((!sem) || !(sem->unamed)) + { + rt_set_errno(EINVAL); + + return -1; + } + + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + result = rt_sem_trytake(sem->sem); + if (result != RT_EOK) + { + rt_sem_release(&posix_sem_lock); + rt_set_errno(EBUSY); + + return -1; + } + + /* destroy an unamed posix semaphore */ + posix_sem_delete(sem); + rt_sem_release(&posix_sem_lock); + + return 0; +} +RTM_EXPORT(sem_destroy); + +int sem_unlink(const char *name) +{ + sem_t *psem; + + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + psem = posix_sem_find(name); + if (psem != RT_NULL) + { + psem->unlinked = 1; + if (psem->refcount == 0) + { + /* remove this semaphore */ + posix_sem_delete(psem); + } + rt_sem_release(&posix_sem_lock); + + return 0; + } + rt_sem_release(&posix_sem_lock); + + /* no this entry */ + rt_set_errno(ENOENT); + + return -1; +} +RTM_EXPORT(sem_unlink); + +int sem_getvalue(sem_t *sem, int *sval) +{ + if (!sem || !sval) + { + rt_set_errno(EINVAL); + + return -1; + } + *sval = sem->sem->value; + + return 0; +} +RTM_EXPORT(sem_getvalue); + +int sem_init(sem_t *sem, int pshared, unsigned int value) +{ + char name[RT_NAME_MAX]; + static rt_uint16_t psem_number = 0; + + if (sem == RT_NULL) + { + rt_set_errno(EINVAL); + + return -1; + } + + rt_snprintf(name, sizeof(name), "psem%02d", psem_number++); + sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO); + if (sem->sem == RT_NULL) + { + rt_set_errno(ENOMEM); + + return -1; + } + + /* initialize posix semaphore */ + sem->refcount = 1; + sem->unlinked = 0; + sem->unamed = 1; + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + posix_sem_insert(sem); + rt_sem_release(&posix_sem_lock); + + return 0; +} +RTM_EXPORT(sem_init); + +sem_t *sem_open(const char *name, int oflag, ...) +{ + sem_t* sem; + va_list arg; + mode_t mode; + unsigned int value; + + sem = RT_NULL; + + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + if (oflag & O_CREAT) + { + va_start(arg, oflag); + mode = (mode_t) va_arg( arg, unsigned int); mode = mode; + value = va_arg( arg, unsigned int); + va_end(arg); + + if (oflag & O_EXCL) + { + if (posix_sem_find(name) != RT_NULL) + { + rt_set_errno(EEXIST); + goto __return; + } + } + sem = (sem_t*) rt_malloc (sizeof(struct posix_sem)); + if (sem == RT_NULL) + { + rt_set_errno(ENFILE); + goto __return; + } + + /* create RT-Thread semaphore */ + sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO); + if (sem->sem == RT_NULL) /* create failed */ + { + rt_set_errno(ENFILE); + goto __return; + } + /* initialize reference count */ + sem->refcount = 1; + sem->unlinked = 0; + sem->unamed = 0; + + /* insert semaphore to posix semaphore list */ + posix_sem_insert(sem); + } + else + { + /* find semaphore */ + sem = posix_sem_find(name); + if (sem != RT_NULL) + { + sem->refcount ++; /* increase reference count */ + } + else + { + rt_set_errno(ENOENT); + goto __return; + } + } + rt_sem_release(&posix_sem_lock); + + return sem; + +__return: + /* release lock */ + rt_sem_release(&posix_sem_lock); + + /* release allocated memory */ + if (sem != RT_NULL) + { + /* delete RT-Thread semaphore */ + if (sem->sem != RT_NULL) + rt_sem_delete(sem->sem); + rt_free(sem); + } + + return RT_NULL; +} +RTM_EXPORT(sem_open); + +int sem_post(sem_t *sem) +{ + rt_err_t result; + + if (!sem) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_sem_release(sem->sem); + if (result == RT_EOK) + return 0; + + rt_set_errno(EINVAL); + + return -1; +} +RTM_EXPORT(sem_post); + +int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout) +{ + rt_err_t result; + rt_int32_t tick; + + if (!sem || !abs_timeout) + return EINVAL; + + /* calculate os tick */ + tick = rt_timespec_to_tick(abs_timeout); + + result = rt_sem_take(sem->sem, tick); + if (result == -RT_ETIMEOUT) + { + rt_set_errno(ETIMEDOUT); + + return -1; + } + if (result == RT_EOK) + return 0; + + rt_set_errno(EINTR); + + return -1; +} +RTM_EXPORT(sem_timedwait); + +int sem_trywait(sem_t *sem) +{ + rt_err_t result; + + if (!sem) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_sem_take(sem->sem, 0); + if (result == -RT_ETIMEOUT) + { + rt_set_errno(EAGAIN); + + return -1; + } + if (result == RT_EOK) + return 0; + + rt_set_errno(EINTR); + + return -1; +} +RTM_EXPORT(sem_trywait); + +int sem_wait(sem_t *sem) +{ + rt_err_t result; + + if (!sem) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_sem_take(sem->sem, RT_WAITING_FOREVER); + if (result == RT_EOK) + return 0; + + rt_set_errno(EINTR); + + return -1; +} +RTM_EXPORT(sem_wait); + diff --git a/components/libc/posix/pthreads/semaphore.h b/components/libc/posix/pthreads/semaphore.h new file mode 100644 index 0000000000..872226e385 --- /dev/null +++ b/components/libc/posix/pthreads/semaphore.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2010-10-26 Bernard the first version + */ + +#ifndef __POSIX_SEMAPHORE_H__ +#define __POSIX_SEMAPHORE_H__ + +#include +#include + +struct posix_sem +{ + /* reference count and unlinked */ + rt_uint16_t refcount; + rt_uint8_t unlinked; + rt_uint8_t unamed; + + /* RT-Thread semaphore */ + rt_sem_t sem; + + /* next posix semaphore */ + struct posix_sem* next; +}; +typedef struct posix_sem sem_t; + +int sem_close(sem_t *sem); +int sem_destroy(sem_t *sem); +int sem_getvalue(sem_t *sem, int *sval); +int sem_init(sem_t *sem, int pshared, unsigned int value); +sem_t *sem_open(const char *name, int oflag, ...); +int sem_post(sem_t *sem); +int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); +int sem_trywait(sem_t *sem); +int sem_unlink(const char *name); +int sem_wait(sem_t *sem); + +#endif diff --git a/components/libc/posix/signal/SConscript b/components/libc/posix/signal/SConscript new file mode 100644 index 0000000000..f07ff58f6e --- /dev/null +++ b/components/libc/posix/signal/SConscript @@ -0,0 +1,13 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('libc', src, + depend = ['RT_USING_SIGNALS', 'RT_USING_PTHREADS', 'RT_USING_LIBC'], + CPPPATH = CPPPATH) + +Return('group') diff --git a/components/libc/posix/signal/posix_signal.c b/components/libc/posix/signal/posix_signal.c new file mode 100644 index 0000000000..ac8d2b1eef --- /dev/null +++ b/components/libc/posix/signal/posix_signal.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017/10/1 Bernard The first version + */ + +#include +#include + +#include +#include + +#include "posix_signal.h" + +#define sig_valid(sig_no) (sig_no >= 0 && sig_no < RT_SIG_MAX) + +void (*signal(int sig, void (*func)(int))) (int) +{ + return rt_signal_install(sig, func); +} + +int sigprocmask (int how, const sigset_t *set, sigset_t *oset) +{ + rt_base_t level; + rt_thread_t tid; + + tid = rt_thread_self(); + + level = rt_hw_interrupt_disable(); + if (oset) *oset = tid->sig_mask; + + if (set) + { + switch(how) + { + case SIG_BLOCK: + tid->sig_mask |= *set; + break; + case SIG_UNBLOCK: + tid->sig_mask &= ~*set; + break; + case SIG_SETMASK: + tid->sig_mask = *set; + break; + default: + break; + } + } + rt_hw_interrupt_enable(level); + + return 0; +} + +int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) +{ + rt_sighandler_t old = RT_NULL; + + if (!sig_valid(signum)) return -RT_ERROR; + + if (act) + old = rt_signal_install(signum, act->sa_handler); + else + { + old = rt_signal_install(signum, RT_NULL); + rt_signal_install(signum, old); + } + + if (oldact) + oldact->sa_handler = old; + + return 0; +} + +int sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) +{ + int ret = 0; + int tick = RT_WAITING_FOREVER; + + if (timeout) + { + tick = rt_timespec_to_tick(timeout); + } + + ret = rt_signal_wait(set, info, tick); + if (ret == 0) return 0; + + errno = ret; + return -1; +} + +int sigwait(const sigset_t *set, int *sig) +{ + siginfo_t si; + if (sigtimedwait(set, &si, 0) < 0) + return -1; + + *sig = si.si_signo; + return 0; +} + +int sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ + return sigtimedwait(set, info, NULL); +} + +int raise(int sig) +{ + rt_thread_kill(rt_thread_self(), sig); + return 0; +} + diff --git a/components/libc/posix/signal/posix_signal.h b/components/libc/posix/signal/posix_signal.h new file mode 100644 index 0000000000..f04b54c5f8 --- /dev/null +++ b/components/libc/posix/signal/posix_signal.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017/10/1 Bernard The first version + */ + +#ifndef POSIX_SIGNAL_H__ +#define POSIX_SIGNAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum rt_signal_value{ + SIG1 = SIGHUP, + SIG2 = SIGINT, + SIG3 = SIGQUIT, + SIG4 = SIGILL, + SIG5 = SIGTRAP, + SIG6 = SIGABRT, + SIG7 = SIGEMT, + SIG8 = SIGFPE, + SIG9 = SIGKILL, + SIG10 = SIGBUS, + SIG11 = SIGSEGV, + SIG12 = SIGSYS, + SIG13 = SIGPIPE, + SIG14 = SIGALRM, + SIG15 = SIGTERM, + SIG16 = SIGURG, + SIG17 = SIGSTOP, + SIG18 = SIGTSTP, + SIG19 = SIGCONT, + SIG20 = SIGCHLD, + SIG21 = SIGTTIN, + SIG22 = SIGTTOU, + SIG23 = SIGPOLL, + SIG24 = 24, // SIGXCPU, + SIG25 = 25, // SIGXFSZ, + SIG26 = 26, // SIGVTALRM, + SIG27 = 27, // SIGPROF, + SIG28 = SIGWINCH, + SIG29 = 29, // SIGLOST, + SIG30 = SIGUSR1, + SIG31 = SIGUSR2, + SIGRT_MIN = 27, // SIGRTMIN, + SIGRT_MAX = 31, // SIGRTMAX, + SIGMAX = NSIG, +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/libc/posix/termios/SConscript b/components/libc/posix/termios/SConscript new file mode 100644 index 0000000000..381eb5ad8b --- /dev/null +++ b/components/libc/posix/termios/SConscript @@ -0,0 +1,13 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('libc', src, + depend = ['RT_USING_LIBC', 'RT_USING_POSIX', 'RT_USING_POSIX_TERMIOS'], + CPPPATH = CPPPATH) + +Return('group') diff --git a/components/libc/posix/termios/posix_termios.c b/components/libc/posix/termios/posix_termios.c new file mode 100644 index 0000000000..9f33c857e6 --- /dev/null +++ b/components/libc/posix/termios/posix_termios.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017/08/30 Bernard The first version + */ +#include +#include +#include +#include +#include + +int tcgetattr(int fd, struct termios *tio) +{ + /* Get the current serial port settings. */ + if (ioctl(fd, TCGETA, tio)) + return -1; + + return 0; +} + +int tcsetattr(int fd, int act, const struct termios *tio) +{ + switch (act) + { + case TCSANOW: + /* make the change immediately */ + return (ioctl(fd, TCSETA, (void*)tio)); + case TCSADRAIN: + /* + * Don't make the change until all currently written data + * has been transmitted. + */ + return (ioctl(fd, TCSETAW, (void*)tio)); + case TCSAFLUSH: + /* Don't make the change until all currently written data + * has been transmitted, at which point any received but + * unread data is also discarded. + */ + return (ioctl(fd, TCSETAF, (void*)tio)); + default: + errno = EINVAL; + return (-1); + } +} + +/** + * this function gets process group ID for session leader for controlling + * terminal + * + * @return always 0 + */ +pid_t tcgetsid(int fd) +{ + return 0; +} + +speed_t cfgetospeed(const struct termios *tio) +{ + return tio->c_cflag & CBAUD; +} + +speed_t cfgetispeed(const struct termios *tio) +{ + return cfgetospeed(tio); +} + +int cfsetospeed(struct termios *tio, speed_t speed) +{ + if (speed & ~CBAUD) + { + errno = EINVAL; + return -1; + } + + tio->c_cflag &= ~CBAUD; + tio->c_cflag |= speed; + return 0; +} + +int cfsetispeed(struct termios *tio, speed_t speed) +{ + return speed ? cfsetospeed(tio, speed) : 0; +} + +int tcsendbreak(int fd, int dur) +{ + /* nonzero duration is implementation-defined, so ignore it */ + return 0; +} + +int tcflush(int fd, int queue) +{ + return ioctl(fd, TCFLSH, (void*)queue); +} + +int tcflow(int fd, int action) +{ + return ioctl(fd, TCXONC, (void*)action); +} + +/** + * this function waits for transmission of output + */ +int tcdrain(int fd) +{ + return 0; +} + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +void cfmakeraw(struct termios *t) +{ + t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + t->c_oflag &= ~OPOST; + t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + t->c_cflag &= ~(CSIZE|PARENB); + t->c_cflag |= CS8; + t->c_cc[VMIN] = 1; + t->c_cc[VTIME] = 0; +} + +int cfsetspeed(struct termios *tio, speed_t speed) +{ + return cfsetospeed(tio, speed); +} +#endif diff --git a/components/libc/posix/termios/posix_termios.h b/components/libc/posix/termios/posix_termios.h new file mode 100644 index 0000000000..6dc5531955 --- /dev/null +++ b/components/libc/posix/termios/posix_termios.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017/08/30 Bernard The first version + */ +#ifndef TERMIOS_H__ +#define TERMIOS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 32 + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t __c_ispeed; + speed_t __c_ospeed; +}; + +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 + +#define B0 0000000 +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 + +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 + +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 + +#define ISIG 0000001 +#define ICANON 0000002 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define IEXTEN 0100000 + +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#define EXTA 0000016 +#define EXTB 0000017 +#define CBAUD 0010017 +#define CBAUDEX 0010000 +#define CIBAUD 002003600000 +#define CMSPAR 010000000000 +#define CRTSCTS 020000000000 + +#define XCASE 0000004 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define EXTPROC 0200000 + +#define XTABS 0014000 + +speed_t cfgetospeed (const struct termios *); +speed_t cfgetispeed (const struct termios *); +int cfsetospeed (struct termios *, speed_t); +int cfsetispeed (struct termios *, speed_t); + +int tcgetattr (int, struct termios *); +int tcsetattr (int, int, const struct termios *); + +int tcsendbreak (int, int); +int tcdrain (int); +int tcflush (int, int); +int tcflow (int, int); + +pid_t tcgetsid (int); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +void cfmakeraw(struct termios *); +int cfsetspeed(struct termios *, speed_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/libc/pthreads/SConscript b/components/libc/pthreads/SConscript deleted file mode 100644 index 767b406d4c..0000000000 --- a/components/libc/pthreads/SConscript +++ /dev/null @@ -1,22 +0,0 @@ -from building import * -from utils import VersionCmp - -cwd = GetCurrentDir() -src = Glob('*.c') -CPPPATH = [cwd] -CPPDEFINES = [] - -# only enable POSIX.1b-1993 Real-time extensions -libc_ver = GetDepend('LIBC_VERSION') -try: - ver = libc_ver.split(' ') - ver = ver[1] - if VersionCmp(ver, "2.5.0") == 1: - CPPDEFINES = ['_POSIX_C_SOURCE=199309L'] -except : - pass - -group = DefineGroup('libc', src, - depend = ['RT_USING_PTHREADS', 'RT_USING_LIBC'], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) - -Return('group') diff --git a/components/libc/pthreads/mqueue.c b/components/libc/pthreads/mqueue.c deleted file mode 100644 index 6840164a68..0000000000 --- a/components/libc/pthreads/mqueue.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - */ - -#include -#include -#include "mqueue.h" -#include "pthread_internal.h" - -static mqd_t posix_mq_list = RT_NULL; -static struct rt_semaphore posix_mq_lock; -void posix_mq_system_init() -{ - rt_sem_init(&posix_mq_lock, "pmq", 1, RT_IPC_FLAG_FIFO); -} - -rt_inline void posix_mq_insert(mqd_t pmq) -{ - pmq->next = posix_mq_list; - posix_mq_list = pmq; -} - -static void posix_mq_delete(mqd_t pmq) -{ - mqd_t iter; - if (posix_mq_list == pmq) - { - posix_mq_list = pmq->next; - - rt_mq_delete(pmq->mq); - rt_free(pmq); - - return; - } - for (iter = posix_mq_list; iter->next != RT_NULL; iter = iter->next) - { - if (iter->next == pmq) - { - /* delete this mq */ - if (pmq->next != RT_NULL) - iter->next = pmq->next; - else - iter->next = RT_NULL; - - /* delete RT-Thread mqueue */ - rt_mq_delete(pmq->mq); - rt_free(pmq); - - return ; - } - } -} - -static mqd_t posix_mq_find(const char* name) -{ - mqd_t iter; - rt_object_t object; - - for (iter = posix_mq_list; iter != RT_NULL; iter = iter->next) - { - object = (rt_object_t)(iter->mq); - - if (strncmp(object->name, name, RT_NAME_MAX) == 0) - { - return iter; - } - } - - return RT_NULL; -} - -int mq_setattr(mqd_t mqdes, - const struct mq_attr *mqstat, - struct mq_attr *omqstat) -{ - rt_set_errno(-RT_ERROR); - - return -1; -} -RTM_EXPORT(mq_setattr); - -int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat) -{ - if ((mqdes == RT_NULL) || mqstat == RT_NULL) - { - rt_set_errno(EBADF); - - return -1; - } - - mqstat->mq_maxmsg = mqdes->mq->max_msgs; - mqstat->mq_msgsize = mqdes->mq->msg_size; - mqstat->mq_curmsgs = 0; - mqstat->mq_flags = 0; - - return 0; -} -RTM_EXPORT(mq_getattr); - -mqd_t mq_open(const char *name, int oflag, ...) -{ - mqd_t mqdes; - va_list arg; - mode_t mode; - struct mq_attr *attr = RT_NULL; - - /* lock posix mqueue list */ - rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); - - mqdes = RT_NULL; - if (oflag & O_CREAT) - { - va_start(arg, oflag); - mode = (mode_t)va_arg(arg, unsigned int); - mode = mode; - attr = (struct mq_attr *)va_arg(arg, struct mq_attr *); - va_end(arg); - - if (oflag & O_EXCL) - { - if (posix_mq_find(name) != RT_NULL) - { - rt_set_errno(EEXIST); - goto __return; - } - } - mqdes = (mqd_t) rt_malloc (sizeof(struct mqdes)); - if (mqdes == RT_NULL) - { - rt_set_errno(ENFILE); - goto __return; - } - - /* create RT-Thread message queue */ - mqdes->mq = rt_mq_create(name, attr->mq_msgsize, attr->mq_maxmsg, RT_IPC_FLAG_FIFO); - if (mqdes->mq == RT_NULL) /* create failed */ - { - rt_set_errno(ENFILE); - goto __return; - } - /* initialize reference count */ - mqdes->refcount = 1; - mqdes->unlinked = 0; - - /* insert mq to posix mq list */ - posix_mq_insert(mqdes); - } - else - { - /* find mqueue */ - mqdes = posix_mq_find(name); - if (mqdes != RT_NULL) - { - mqdes->refcount ++; /* increase reference count */ - } - else - { - rt_set_errno(ENOENT); - goto __return; - } - } - rt_sem_release(&posix_mq_lock); - - return mqdes; - -__return: - /* release lock */ - rt_sem_release(&posix_mq_lock); - - /* release allocated memory */ - if (mqdes != RT_NULL) - { - if (mqdes->mq != RT_NULL) - { - /* delete RT-Thread message queue */ - rt_mq_delete(mqdes->mq); - } - rt_free(mqdes); - } - return RT_NULL; -} -RTM_EXPORT(mq_open); - -ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio) -{ - rt_err_t result; - - if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) - { - rt_set_errno(EINVAL); - - return -1; - } - - result = rt_mq_recv(mqdes->mq, msg_ptr, msg_len, RT_WAITING_FOREVER); - if (result == RT_EOK) - return msg_len; - - rt_set_errno(EBADF); - return -1; -} -RTM_EXPORT(mq_receive); - -int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio) -{ - rt_err_t result; - - if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) - { - rt_set_errno(EINVAL); - - return -1; - } - - result = rt_mq_send(mqdes->mq, (void*)msg_ptr, msg_len); - if (result == RT_EOK) - return 0; - - rt_set_errno(EBADF); - - return -1; -} -RTM_EXPORT(mq_send); - -ssize_t mq_timedreceive(mqd_t mqdes, - char *msg_ptr, - size_t msg_len, - unsigned *msg_prio, - const struct timespec *abs_timeout) -{ - int tick; - rt_err_t result; - - /* parameters check */ - if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) - { - rt_set_errno(EINVAL); - - return -1; - } - - tick = rt_timespec_to_tick(abs_timeout); - - result = rt_mq_recv(mqdes->mq, msg_ptr, msg_len, tick); - if (result == RT_EOK) - return msg_len; - - if (result == -RT_ETIMEOUT) - rt_set_errno(ETIMEDOUT); - else - rt_set_errno(EBADMSG); - - return -1; -} -RTM_EXPORT(mq_timedreceive); - -int mq_timedsend(mqd_t mqdes, - const char *msg_ptr, - size_t msg_len, - unsigned msg_prio, - const struct timespec *abs_timeout) -{ - /* RT-Thread does not support timed send */ - return mq_send(mqdes, msg_ptr, msg_len, msg_prio); -} -RTM_EXPORT(mq_timedsend); - -int mq_notify(mqd_t mqdes, const struct sigevent *notification) -{ - rt_set_errno(-RT_ERROR); - - return -1; -} -RTM_EXPORT(mq_notify); - -int mq_close(mqd_t mqdes) -{ - if (mqdes == RT_NULL) - { - rt_set_errno(EINVAL); - - return -1; - } - - /* lock posix mqueue list */ - rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); - mqdes->refcount --; - if (mqdes->refcount == 0) - { - /* delete from posix mqueue list */ - if (mqdes->unlinked) - posix_mq_delete(mqdes); - } - rt_sem_release(&posix_mq_lock); - - return 0; -} -RTM_EXPORT(mq_close); - -int mq_unlink(const char *name) -{ - mqd_t pmq; - - /* lock posix mqueue list */ - rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); - pmq = posix_mq_find(name); - if (pmq != RT_NULL) - { - pmq->unlinked = 1; - if (pmq->refcount == 0) - { - /* remove this mqueue */ - posix_mq_delete(pmq); - } - rt_sem_release(&posix_mq_lock); - - return 0; - } - rt_sem_release(&posix_mq_lock); - - /* no this entry */ - rt_set_errno(ENOENT); - - return -1; -} -RTM_EXPORT(mq_unlink); diff --git a/components/libc/pthreads/mqueue.h b/components/libc/pthreads/mqueue.h deleted file mode 100644 index 5152bfad29..0000000000 --- a/components/libc/pthreads/mqueue.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - */ - -#ifndef __MQUEUE_H__ -#define __MQUEUE_H__ - -#include -#include - -struct mqdes -{ - /* reference count and unlinked */ - rt_uint16_t refcount; - rt_uint16_t unlinked; - - /* RT-Thread message queue */ - rt_mq_t mq; - /* next posix mqueue */ - struct mqdes* next; -}; -typedef struct mqdes* mqd_t; - -struct mq_attr -{ - long mq_flags; /* Message queue flags. */ - long mq_maxmsg; /* Maximum number of messages. */ - long mq_msgsize; /* Maximum message size. */ - long mq_curmsgs; /* Number of messages currently queued. */ -}; - -int mq_close(mqd_t mqdes); -int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); -int mq_notify(mqd_t mqdes, const struct sigevent *notification); -mqd_t mq_open(const char *name, int oflag, ...); -ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); -int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); -int mq_setattr(mqd_t mqdes, - const struct mq_attr *mqstat, - struct mq_attr *omqstat); -ssize_t mq_timedreceive(mqd_t mqdes, - char *msg_ptr, - size_t msg_len, - unsigned *msg_prio, - const struct timespec *abs_timeout); -int mq_timedsend(mqd_t mqdes, - const char *msg_ptr, - size_t msg_len, - unsigned msg_prio, - const struct timespec *abs_timeout); - -int mq_unlink(const char *name); - -#endif diff --git a/components/libc/pthreads/posix_types.h b/components/libc/pthreads/posix_types.h deleted file mode 100644 index 5838e8b370..0000000000 --- a/components/libc/pthreads/posix_types.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2013-12-23 Bernard Add the checking for ESHUTDOWN - */ - -#ifndef __POSIX_TYPES_H__ -#define __POSIX_TYPES_H__ - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#endif - diff --git a/components/libc/pthreads/pthread.c b/components/libc/pthreads/pthread.c deleted file mode 100644 index b0bf39dff6..0000000000 --- a/components/libc/pthreads/pthread.c +++ /dev/null @@ -1,748 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2018-01-26 Bernard Fix pthread_detach issue for a none-joinable - * thread. - * 2019-02-07 Bernard Add _pthread_destroy to release pthread resource. - */ - -#include -#include -#include -#include -#include "pthread_internal.h" - -RT_DEFINE_SPINLOCK(pth_lock); -_pthread_data_t *pth_table[PTHREAD_NUM_MAX] = {NULL}; - -_pthread_data_t *_pthread_get_data(pthread_t thread) -{ - RT_DECLARE_SPINLOCK(pth_lock); - _pthread_data_t *ptd; - - if (thread >= PTHREAD_NUM_MAX) return NULL; - - rt_hw_spin_lock(&pth_lock); - ptd = pth_table[thread]; - rt_hw_spin_unlock(&pth_lock); - - if (ptd && ptd->magic == PTHREAD_MAGIC) return ptd; - - return NULL; -} - -pthread_t _pthread_data_get_pth(_pthread_data_t *ptd) -{ - int index; - RT_DECLARE_SPINLOCK(pth_lock); - - rt_hw_spin_lock(&pth_lock); - for (index = 0; index < PTHREAD_NUM_MAX; index ++) - { - if (pth_table[index] == ptd) break; - } - rt_hw_spin_unlock(&pth_lock); - - return index; -} - -pthread_t _pthread_data_create(void) -{ - int index; - _pthread_data_t *ptd = NULL; - RT_DECLARE_SPINLOCK(pth_lock); - - ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t)); - if (!ptd) return PTHREAD_NUM_MAX; - - memset(ptd, 0x0, sizeof(_pthread_data_t)); - ptd->canceled = 0; - ptd->cancelstate = PTHREAD_CANCEL_DISABLE; - ptd->canceltype = PTHREAD_CANCEL_DEFERRED; - ptd->magic = PTHREAD_MAGIC; - - rt_hw_spin_lock(&pth_lock); - for (index = 0; index < PTHREAD_NUM_MAX; index ++) - { - if (pth_table[index] == NULL) - { - pth_table[index] = ptd; - break; - } - } - rt_hw_spin_unlock(&pth_lock); - - /* full of pthreads, clean magic and release ptd */ - if (index == PTHREAD_NUM_MAX) - { - ptd->magic = 0x0; - rt_free(ptd); - } - - return index; -} - -void _pthread_data_destroy(pthread_t pth) -{ - RT_DECLARE_SPINLOCK(pth_lock); - - extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; - _pthread_data_t *ptd = _pthread_get_data(pth); - if (ptd) - { - /* destruct thread local key */ - if (ptd->tls != RT_NULL) - { - void *data; - rt_uint32_t index; - for (index = 0; index < PTHREAD_KEY_MAX; index ++) - { - if (_thread_keys[index].is_used) - { - data = ptd->tls[index]; - if (data && _thread_keys[index].destructor) - _thread_keys[index].destructor(data); - } - } - - /* release tls area */ - rt_free(ptd->tls); - ptd->tls = RT_NULL; - } - - /* remove from pthread table */ - rt_hw_spin_lock(&pth_lock); - pth_table[pth] = NULL; - rt_hw_spin_unlock(&pth_lock); - - /* delete joinable semaphore */ - if (ptd->joinable_sem != RT_NULL) - rt_sem_delete(ptd->joinable_sem); - - /* release thread resource */ - if (ptd->attr.stackaddr == RT_NULL) - { - /* release thread allocated stack */ - if (ptd->tid) - { - rt_free(ptd->tid->stack_addr); - } - } - /* clean stack addr pointer */ - if (ptd->tid) - ptd->tid->stack_addr = RT_NULL; - - /* - * if this thread create the local thread data, - * delete it - */ - if (ptd->tls != RT_NULL) rt_free(ptd->tls); - rt_free(ptd->tid); - - /* clean magic */ - ptd->magic = 0x0; - - /* free ptd */ - rt_free(ptd); - } -} - -int pthread_system_init(void) -{ - /* initialize key area */ - pthread_key_system_init(); - /* initialize posix mqueue */ - posix_mq_system_init(); - /* initialize posix semaphore */ - posix_sem_system_init(); - - return 0; -} -INIT_COMPONENT_EXPORT(pthread_system_init); - -static void _pthread_destroy(_pthread_data_t *ptd) -{ - pthread_t pth = _pthread_data_get_pth(ptd); - if (pth != PTHREAD_NUM_MAX) - { - _pthread_data_destroy(pth); - } - - return; -} - -static void _pthread_cleanup(rt_thread_t tid) -{ - _pthread_data_t *ptd; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)tid->user_data; - RT_ASSERT(ptd != RT_NULL); - - /* clear cleanup function */ - tid->cleanup = RT_NULL; - if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) - { - rt_sem_release(ptd->joinable_sem); - } - else - { - /* release pthread resource */ - _pthread_destroy(ptd); - } -} - -static void pthread_entry_stub(void *parameter) -{ - void *value; - _pthread_data_t *ptd; - - ptd = (_pthread_data_t *)parameter; - - /* execute pthread entry */ - value = ptd->thread_entry(ptd->thread_parameter); - /* set value */ - ptd->return_value = value; -} - -int pthread_create(pthread_t *pid, - const pthread_attr_t *attr, - void *(*start)(void *), void *parameter) -{ - int ret = 0; - void *stack; - char name[RT_NAME_MAX]; - static rt_uint16_t pthread_number = 0; - - pthread_t pth_id; - _pthread_data_t *ptd; - - /* pid shall be provided */ - RT_ASSERT(pid != RT_NULL); - - /* allocate posix thread data */ - pth_id = _pthread_data_create(); - if (pth_id == PTHREAD_NUM_MAX) - { - ret = ENOMEM; - goto __exit; - } - /* get pthread data */ - ptd = _pthread_get_data(pth_id); - - RT_ASSERT(ptd != RT_NULL); - - if (attr != RT_NULL) - { - ptd->attr = *attr; - } - else - { - /* use default attribute */ - pthread_attr_init(&ptd->attr); - } - - if (ptd->attr.stacksize == 0) - { - ret = EINVAL; - goto __exit; - } - - rt_snprintf(name, sizeof(name), "pth%02d", pthread_number ++); - - /* pthread is a static thread object */ - ptd->tid = (rt_thread_t) rt_malloc(sizeof(struct rt_thread)); - if (ptd->tid == RT_NULL) - { - ret = ENOMEM; - goto __exit; - } - memset(ptd->tid, 0, sizeof(struct rt_thread)); - - if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) - { - ptd->joinable_sem = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO); - if (ptd->joinable_sem == RT_NULL) - { - ret = ENOMEM; - goto __exit; - } - } - else - { - ptd->joinable_sem = RT_NULL; - } - - /* set parameter */ - ptd->thread_entry = start; - ptd->thread_parameter = parameter; - - /* stack */ - if (ptd->attr.stackaddr == 0) - { - stack = (void *)rt_malloc(ptd->attr.stacksize); - } - else - { - stack = (void *)(ptd->attr.stackaddr); - } - - if (stack == RT_NULL) - { - ret = ENOMEM; - goto __exit; - } - - /* initial this pthread to system */ - if (rt_thread_init(ptd->tid, name, pthread_entry_stub, ptd, - stack, ptd->attr.stacksize, - ptd->attr.schedparam.sched_priority, 20) != RT_EOK) - { - ret = EINVAL; - goto __exit; - } - - /* set pthread id */ - *pid = pth_id; - - /* set pthread cleanup function and ptd data */ - ptd->tid->cleanup = _pthread_cleanup; - ptd->tid->user_data = (rt_ubase_t)ptd; - - /* start thread */ - if (rt_thread_startup(ptd->tid) == RT_EOK) - return 0; - - /* start thread failed */ - rt_thread_detach(ptd->tid); - ret = EINVAL; - -__exit: - if (pth_id != PTHREAD_NUM_MAX) - _pthread_data_destroy(pth_id); - return ret; -} -RTM_EXPORT(pthread_create); - -int pthread_detach(pthread_t thread) -{ - int ret = 0; - _pthread_data_t *ptd = _pthread_get_data(thread); - if (ptd == RT_NULL) - { - /* invalid pthread id */ - ret = EINVAL; - goto __exit; - } - - rt_enter_critical(); - if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED) - { - /* The implementation has detected that the value specified by thread does not refer - * to a joinable thread. - */ - ret = EINVAL; - goto __exit; - } - - if ((ptd->tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) - { - /* this defunct pthread is not handled by idle */ - if (rt_sem_trytake(ptd->joinable_sem) != RT_EOK) - { - rt_sem_release(ptd->joinable_sem); - - /* change to detach state */ - ptd->attr.detachstate = PTHREAD_CREATE_DETACHED; - - /* detach joinable semaphore */ - if (ptd->joinable_sem) - { - rt_sem_delete(ptd->joinable_sem); - ptd->joinable_sem = RT_NULL; - } - } - else - { - /* destroy this pthread */ - _pthread_destroy(ptd); - } - - goto __exit; - } - else - { - /* change to detach state */ - ptd->attr.detachstate = PTHREAD_CREATE_DETACHED; - - /* detach joinable semaphore */ - if (ptd->joinable_sem) - { - rt_sem_delete(ptd->joinable_sem); - ptd->joinable_sem = RT_NULL; - } - } - -__exit: - rt_exit_critical(); - return ret; -} -RTM_EXPORT(pthread_detach); - -int pthread_join(pthread_t thread, void **value_ptr) -{ - _pthread_data_t *ptd; - rt_err_t result; - - ptd = _pthread_get_data(thread); - - if (ptd == RT_NULL) - { - return EINVAL; /* invalid pthread id */ - } - - if (ptd && ptd->tid == rt_thread_self()) - { - /* join self */ - return EDEADLK; - } - - if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED) - { - return EINVAL; /* join on a detached pthread */ - } - - result = rt_sem_take(ptd->joinable_sem, RT_WAITING_FOREVER); - if (result == RT_EOK) - { - /* get return value */ - if (value_ptr != RT_NULL) - *value_ptr = ptd->return_value; - - /* destroy this pthread */ - _pthread_destroy(ptd); - } - else - { - return ESRCH; - } - - return 0; -} -RTM_EXPORT(pthread_join); - -pthread_t pthread_self (void) -{ - rt_thread_t tid; - _pthread_data_t *ptd; - - tid = rt_thread_self(); - if (tid == NULL) return PTHREAD_NUM_MAX; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - RT_ASSERT(ptd != RT_NULL); - - return _pthread_data_get_pth(ptd); -} -RTM_EXPORT(pthread_self); - -void pthread_exit(void *value) -{ - _pthread_data_t *ptd; - _pthread_cleanup_t *cleanup; - extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; - - if (rt_thread_self() == NULL) return; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - - rt_enter_critical(); - /* disable cancel */ - ptd->cancelstate = PTHREAD_CANCEL_DISABLE; - /* set return value */ - ptd->return_value = value; - rt_exit_critical(); - - /* invoke pushed cleanup */ - while (ptd->cleanup != RT_NULL) - { - cleanup = ptd->cleanup; - ptd->cleanup = cleanup->next; - - cleanup->cleanup_func(cleanup->parameter); - /* release this cleanup function */ - rt_free(cleanup); - } - - /* destruct thread local key */ - if (ptd->tls != RT_NULL) - { - void *data; - rt_uint32_t index; - - for (index = 0; index < PTHREAD_KEY_MAX; index ++) - { - if (_thread_keys[index].is_used) - { - data = ptd->tls[index]; - if (data && _thread_keys[index].destructor) - _thread_keys[index].destructor(data); - } - } - - /* release tls area */ - rt_free(ptd->tls); - ptd->tls = RT_NULL; - } - - /* detach thread */ - rt_thread_detach(ptd->tid); - /* reschedule thread */ - rt_schedule(); -} -RTM_EXPORT(pthread_exit); - -int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) -{ - RT_ASSERT(once_control != RT_NULL); - RT_ASSERT(init_routine != RT_NULL); - - rt_enter_critical(); - if (!(*once_control)) - { - /* call routine once */ - *once_control = 1; - rt_exit_critical(); - - init_routine(); - } - rt_exit_critical(); - - return 0; -} -RTM_EXPORT(pthread_once); - -int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) -{ - return EOPNOTSUPP; -} -RTM_EXPORT(pthread_atfork); - -int pthread_kill(pthread_t thread, int sig) -{ -#ifdef RT_USING_SIGNALS - _pthread_data_t *ptd; - int ret; - - ptd = _pthread_get_data(thread); - if (ptd) - { - ret = rt_thread_kill(ptd->tid, sig); - if (ret == -RT_EINVAL) - { - return EINVAL; - } - - return ret; - } - - return ESRCH; -#else - return ENOSYS; -#endif -} -RTM_EXPORT(pthread_kill); - -#ifdef RT_USING_SIGNALS -int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) -{ - return sigprocmask(how, set, oset); -} -#endif - -void pthread_cleanup_pop(int execute) -{ - _pthread_data_t *ptd; - _pthread_cleanup_t *cleanup; - - if (rt_thread_self() == NULL) return; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - RT_ASSERT(ptd != RT_NULL); - - if (execute) - { - rt_enter_critical(); - cleanup = ptd->cleanup; - if (cleanup) - ptd->cleanup = cleanup->next; - rt_exit_critical(); - - if (cleanup) - { - cleanup->cleanup_func(cleanup->parameter); - - rt_free(cleanup); - } - } -} -RTM_EXPORT(pthread_cleanup_pop); - -void pthread_cleanup_push(void (*routine)(void *), void *arg) -{ - _pthread_data_t *ptd; - _pthread_cleanup_t *cleanup; - - if (rt_thread_self() == NULL) return; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - RT_ASSERT(ptd != RT_NULL); - - cleanup = (_pthread_cleanup_t *)rt_malloc(sizeof(_pthread_cleanup_t)); - if (cleanup != RT_NULL) - { - cleanup->cleanup_func = routine; - cleanup->parameter = arg; - - rt_enter_critical(); - cleanup->next = ptd->cleanup; - ptd->cleanup = cleanup; - rt_exit_critical(); - } -} -RTM_EXPORT(pthread_cleanup_push); - -/* - * According to IEEE Std 1003.1, 2004 Edition , following pthreads - * interface support cancellation point: - * mq_receive() - * mq_send() - * mq_timedreceive() - * mq_timedsend() - * msgrcv() - * msgsnd() - * msync() - * pthread_cond_timedwait() - * pthread_cond_wait() - * pthread_join() - * pthread_testcancel() - * sem_timedwait() - * sem_wait() - * - * A cancellation point may also occur when a thread is - * executing the following functions: - * pthread_rwlock_rdlock() - * pthread_rwlock_timedrdlock() - * pthread_rwlock_timedwrlock() - * pthread_rwlock_wrlock() - * - * The pthread_cancel(), pthread_setcancelstate(), and pthread_setcanceltype() - * functions are defined to be async-cancel safe. - */ - -int pthread_setcancelstate(int state, int *oldstate) -{ - _pthread_data_t *ptd; - - if (rt_thread_self() == NULL) return EINVAL; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - RT_ASSERT(ptd != RT_NULL); - - if ((state == PTHREAD_CANCEL_ENABLE) || (state == PTHREAD_CANCEL_DISABLE)) - { - if (oldstate) - *oldstate = ptd->cancelstate; - ptd->cancelstate = state; - - return 0; - } - - return EINVAL; -} -RTM_EXPORT(pthread_setcancelstate); - -int pthread_setcanceltype(int type, int *oldtype) -{ - _pthread_data_t *ptd; - - if (rt_thread_self() == NULL) return EINVAL; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - RT_ASSERT(ptd != RT_NULL); - - if ((type != PTHREAD_CANCEL_DEFERRED) && (type != PTHREAD_CANCEL_ASYNCHRONOUS)) - return EINVAL; - - if (oldtype) - *oldtype = ptd->canceltype; - ptd->canceltype = type; - - return 0; -} -RTM_EXPORT(pthread_setcanceltype); - -void pthread_testcancel(void) -{ - int cancel = 0; - _pthread_data_t *ptd; - - if (rt_thread_self() == NULL) return; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - RT_ASSERT(ptd != RT_NULL); - - if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE) - cancel = ptd->canceled; - if (cancel) - pthread_exit((void *)PTHREAD_CANCELED); -} -RTM_EXPORT(pthread_testcancel); - -int pthread_cancel(pthread_t thread) -{ - _pthread_data_t *ptd; - - /* get posix thread data */ - ptd = _pthread_get_data(thread); - if (ptd == RT_NULL) - { - return EINVAL; - } - - /* cancel self */ - if (ptd->tid == rt_thread_self()) - return 0; - - /* set canceled */ - if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE) - { - ptd->canceled = 1; - if (ptd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) - { - /* - * to detach thread. - * this thread will be removed from scheduler list - * and because there is a cleanup function in the - * thread (pthread_cleanup), it will move to defunct - * thread list and wait for handling in idle thread. - */ - rt_thread_detach(ptd->tid); - } - } - - return 0; -} -RTM_EXPORT(pthread_cancel); - diff --git a/components/libc/pthreads/pthread.h b/components/libc/pthreads/pthread.h deleted file mode 100644 index 177b2539c5..0000000000 --- a/components/libc/pthreads/pthread.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#ifndef __PTHREAD_H__ -#define __PTHREAD_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#define PTHREAD_KEY_MAX 8 - -#define PTHREAD_COND_INITIALIZER {-1, 0} -#define PTHREAD_RWLOCK_INITIALIZER {-1, 0} -#define PTHREAD_MUTEX_INITIALIZER {-1, 0} - -#define PTHREAD_CREATE_JOINABLE 0x00 -#define PTHREAD_CREATE_DETACHED 0x01 - -#define PTHREAD_EXPLICIT_SCHED 0 -#define PTHREAD_INHERIT_SCHED 1 - -typedef long pthread_t; -typedef long pthread_condattr_t; -typedef long pthread_rwlockattr_t; -typedef long pthread_mutexattr_t; -typedef long pthread_barrierattr_t; - -typedef int pthread_key_t; -typedef int pthread_once_t; - -enum -{ - PTHREAD_CANCEL_ASYNCHRONOUS = 0, - PTHREAD_CANCEL_ENABLE, - PTHREAD_CANCEL_DEFERRED, - PTHREAD_CANCEL_DISABLE, - PTHREAD_CANCELED -}; - -enum -{ - PTHREAD_MUTEX_NORMAL = 0, - PTHREAD_MUTEX_RECURSIVE = 1, - PTHREAD_MUTEX_ERRORCHECK = 2, - PTHREAD_MUTEX_ERRORCHECK_NP = PTHREAD_MUTEX_ERRORCHECK, - PTHREAD_MUTEX_RECURSIVE_NP = PTHREAD_MUTEX_RECURSIVE, - PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL -}; - -/* init value for pthread_once_t */ -#define PTHREAD_ONCE_INIT 0 - -enum -{ - PTHREAD_PRIO_INHERIT =0, - PTHREAD_PRIO_NONE, - PTHREAD_PRIO_PROTECT, -}; - -#define PTHREAD_PROCESS_PRIVATE 0 -#define PTHREAD_PROCESS_SHARED 1 - -#define PTHREAD_SCOPE_PROCESS 0 -#define PTHREAD_SCOPE_SYSTEM 1 - -struct sched_param -{ - int sched_priority; -}; - -struct pthread_attr -{ - void* stackaddr; /* stack address of thread */ - int stacksize; /* stack size of thread */ - - int inheritsched; /* Inherit parent prio/policy */ - int schedpolicy; /* scheduler policy */ - struct sched_param schedparam; /* sched parameter */ - - int detachstate; /* detach state */ -}; -typedef struct pthread_attr pthread_attr_t; - -struct pthread_mutex -{ - pthread_mutexattr_t attr; - struct rt_mutex lock; -}; -typedef struct pthread_mutex pthread_mutex_t; - -struct pthread_cond -{ - pthread_condattr_t attr; - struct rt_semaphore sem; -}; -typedef struct pthread_cond pthread_cond_t; - -struct pthread_rwlock -{ - pthread_rwlockattr_t attr; - - pthread_mutex_t rw_mutex; /* basic lock on this struct */ - pthread_cond_t rw_condreaders; /* for reader threads waiting */ - pthread_cond_t rw_condwriters; /* for writer threads waiting */ - - int rw_nwaitreaders; /* the number of reader threads waiting */ - int rw_nwaitwriters; /* the number of writer threads waiting */ - int rw_refcount; /* 0: unlocked, -1: locked by writer, > 0 locked by n readers */ -}; -typedef struct pthread_rwlock pthread_rwlock_t; - -/* spinlock implementation, (ADVANCED REALTIME THREADS)*/ -struct pthread_spinlock -{ - int lock; -}; -typedef struct pthread_spinlock pthread_spinlock_t; - -struct pthread_barrier -{ - int count; - pthread_cond_t cond; - pthread_mutex_t mutex; -}; -typedef struct pthread_barrier pthread_barrier_t; - -/* pthread thread interface */ -int pthread_attr_destroy(pthread_attr_t *attr); -int pthread_attr_init(pthread_attr_t *attr); -int pthread_attr_setdetachstate(pthread_attr_t *attr, int state); -int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state); -int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); -int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy); -int pthread_attr_setschedparam(pthread_attr_t *attr,struct sched_param const *param); -int pthread_attr_getschedparam(pthread_attr_t const *attr,struct sched_param *param); -int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size); -int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size); -int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr); -int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr); -int pthread_attr_setstack(pthread_attr_t *attr, - void *stack_base, - size_t stack_size); -int pthread_attr_getstack(pthread_attr_t const *attr, - void **stack_base, - size_t *stack_size); -int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard_size); -int pthread_attr_getguardsize(pthread_attr_t const *attr, size_t *guard_size); -int pthread_attr_setscope(pthread_attr_t *attr, int scope); -int pthread_attr_getscope(pthread_attr_t const *attr); -int pthread_system_init(void); -int pthread_create (pthread_t *tid, const pthread_attr_t *attr, - void *(*start) (void *), void *arg); - -int pthread_detach (pthread_t thread); -int pthread_join (pthread_t thread, void **value_ptr); - -rt_inline int pthread_equal (pthread_t t1, pthread_t t2) -{ - return t1 == t2; -} - -pthread_t pthread_self (void); - -void pthread_exit (void *value_ptr); -int pthread_once(pthread_once_t * once_control, void (*init_routine) (void)); - -/* pthread cleanup */ -void pthread_cleanup_pop(int execute); -void pthread_cleanup_push(void (*routine)(void*), void *arg); - -/* pthread cancel */ -int pthread_cancel(pthread_t thread); -void pthread_testcancel(void); -int pthread_setcancelstate(int state, int *oldstate); -int pthread_setcanceltype(int type, int *oldtype); - -int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); -int pthread_kill(pthread_t thread, int sig); - -/* pthread mutex interface */ -int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); -int pthread_mutex_destroy(pthread_mutex_t *mutex); -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_init(pthread_mutexattr_t *attr); -int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); -int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type); -int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); -int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); -int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared); - -/* pthread condition interface */ -int pthread_condattr_destroy(pthread_condattr_t *attr); -int pthread_condattr_init(pthread_condattr_t *attr); - -/* ADVANCED REALTIME feature in IEEE Std 1003.1, 2004 Edition */ -int pthread_condattr_getclock(const pthread_condattr_t *attr, - clockid_t *clock_id); -int pthread_condattr_setclock(pthread_condattr_t *attr, - clockid_t clock_id); - -int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); -int pthread_cond_destroy(pthread_cond_t *cond); -int pthread_cond_broadcast(pthread_cond_t *cond); -int pthread_cond_signal(pthread_cond_t *cond); - -int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); -int pthread_cond_timedwait(pthread_cond_t *cond, - pthread_mutex_t *mutex, - const struct timespec *abstime); - -/* pthread rwlock interface */ -int pthread_rwlockattr_init (pthread_rwlockattr_t *attr); -int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr); -int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared); -int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); - -int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); -int pthread_rwlock_destroy (pthread_rwlock_t *rwlock); - -int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); -int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); - -int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, const struct timespec *abstime); -int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, const struct timespec *abstime); - -int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); - -int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); -int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); - -/* pthread spinlock interface */ -int pthread_spin_init (pthread_spinlock_t *lock, int pshared); -int pthread_spin_destroy (pthread_spinlock_t *lock); - -int pthread_spin_lock (pthread_spinlock_t * lock); -int pthread_spin_trylock (pthread_spinlock_t * lock); -int pthread_spin_unlock (pthread_spinlock_t * lock); - -/* pthread barrier interface */ -int pthread_barrierattr_destroy(pthread_barrierattr_t *attr); -int pthread_barrierattr_init(pthread_barrierattr_t *attr); -int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared); -int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared); - -int pthread_barrier_destroy(pthread_barrier_t *barrier); -int pthread_barrier_init(pthread_barrier_t *barrier, - const pthread_barrierattr_t *attr, - unsigned count); - -int pthread_barrier_wait(pthread_barrier_t *barrier); - -int pthread_setspecific(pthread_key_t key, const void *value); -void *pthread_getspecific(pthread_key_t key); -int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); -int pthread_key_delete(pthread_key_t key); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/libc/pthreads/pthread_attr.c b/components/libc/pthreads/pthread_attr.c deleted file mode 100644 index 4aedf5a90d..0000000000 --- a/components/libc/pthreads/pthread_attr.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#include -#include "pthread.h" -#include "sched.h" -#include - -#define DEFAULT_STACK_SIZE 2048 -#define DEFAULT_PRIORITY (RT_THREAD_PRIORITY_MAX/2 + RT_THREAD_PRIORITY_MAX/4) - -const pthread_attr_t pthread_default_attr = -{ - 0, /* stack base */ - DEFAULT_STACK_SIZE, /* stack size */ - - PTHREAD_INHERIT_SCHED, /* Inherit parent prio/policy */ - SCHED_FIFO, /* scheduler policy */ - { - DEFAULT_PRIORITY, /* scheduler priority */ - }, - PTHREAD_CREATE_JOINABLE, /* detach state */ -}; - -int pthread_attr_init(pthread_attr_t *attr) -{ - RT_ASSERT(attr != RT_NULL); - - *attr = pthread_default_attr; - - return 0; -} -RTM_EXPORT(pthread_attr_init); - -int pthread_attr_destroy(pthread_attr_t *attr) -{ - RT_ASSERT(attr != RT_NULL); - - memset(attr, 0, sizeof(pthread_attr_t)); - - return 0; -} -RTM_EXPORT(pthread_attr_destroy); - -int pthread_attr_setdetachstate(pthread_attr_t *attr, int state) -{ - RT_ASSERT(attr != RT_NULL); - - if (state != PTHREAD_CREATE_JOINABLE && state != PTHREAD_CREATE_DETACHED) - return EINVAL; - - attr->detachstate = state; - - return 0; -} -RTM_EXPORT(pthread_attr_setdetachstate); - -int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state) -{ - RT_ASSERT(attr != RT_NULL); - - *state = (int)attr->detachstate; - - return 0; -} -RTM_EXPORT(pthread_attr_getdetachstate); - -int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) -{ - RT_ASSERT(attr != RT_NULL); - - attr->schedpolicy = policy; - - return 0; -} -RTM_EXPORT(pthread_attr_setschedpolicy); - -int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy) -{ - RT_ASSERT(attr != RT_NULL); - - *policy = (int)attr->schedpolicy; - - return 0; -} -RTM_EXPORT(pthread_attr_getschedpolicy); - -int pthread_attr_setschedparam(pthread_attr_t *attr, - struct sched_param const *param) -{ - RT_ASSERT(attr != RT_NULL); - RT_ASSERT(param != RT_NULL); - - attr->schedparam.sched_priority = param->sched_priority; - - return 0; -} -RTM_EXPORT(pthread_attr_setschedparam); - -int pthread_attr_getschedparam(pthread_attr_t const *attr, - struct sched_param *param) -{ - RT_ASSERT(attr != RT_NULL); - RT_ASSERT(param != RT_NULL); - - param->sched_priority = attr->schedparam.sched_priority; - - return 0; -} -RTM_EXPORT(pthread_attr_getschedparam); - -int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size) -{ - RT_ASSERT(attr != RT_NULL); - - attr->stacksize = stack_size; - - return 0; -} -RTM_EXPORT(pthread_attr_setstacksize); - -int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size) -{ - RT_ASSERT(attr != RT_NULL); - - *stack_size = attr->stacksize; - - return 0; -} -RTM_EXPORT(pthread_attr_getstacksize); - -int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr) -{ - RT_ASSERT(attr != RT_NULL); - - return EOPNOTSUPP; -} -RTM_EXPORT(pthread_attr_setstackaddr); - -int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr) -{ - RT_ASSERT(attr != RT_NULL); - - return EOPNOTSUPP; -} -RTM_EXPORT(pthread_attr_getstackaddr); - -int pthread_attr_setstack(pthread_attr_t *attr, - void *stack_base, - size_t stack_size) -{ - RT_ASSERT(attr != RT_NULL); - - attr->stackaddr = stack_base; - attr->stacksize = RT_ALIGN_DOWN(stack_size, RT_ALIGN_SIZE); - - return 0; -} -RTM_EXPORT(pthread_attr_setstack); - -int pthread_attr_getstack(pthread_attr_t const *attr, - void **stack_base, - size_t *stack_size) -{ - RT_ASSERT(attr != RT_NULL); - - *stack_base = attr->stackaddr; - *stack_size = attr->stacksize; - - return 0; -} -RTM_EXPORT(pthread_attr_getstack); - -int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard_size) -{ - return EOPNOTSUPP; -} - -int pthread_attr_getguardsize(pthread_attr_t const *attr, size_t *guard_size) -{ - return EOPNOTSUPP; -} -RTM_EXPORT(pthread_attr_getguardsize); - -int pthread_attr_setscope(pthread_attr_t *attr, int scope) -{ - if (scope == PTHREAD_SCOPE_SYSTEM) - return 0; - if (scope == PTHREAD_SCOPE_PROCESS) - return EOPNOTSUPP; - - return EINVAL; -} -RTM_EXPORT(pthread_attr_setscope); - -int pthread_attr_getscope(pthread_attr_t const *attr) -{ - return PTHREAD_SCOPE_SYSTEM; -} -RTM_EXPORT(pthread_attr_getscope); diff --git a/components/libc/pthreads/pthread_barrier.c b/components/libc/pthreads/pthread_barrier.c deleted file mode 100644 index 1a5b7fa3f9..0000000000 --- a/components/libc/pthreads/pthread_barrier.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#include - -int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) -{ - if (!attr) - return EINVAL; - - return 0; -} -RTM_EXPORT(pthread_barrierattr_destroy); - -int pthread_barrierattr_init(pthread_barrierattr_t *attr) -{ - if (!attr) - return EINVAL; - *attr = PTHREAD_PROCESS_PRIVATE; - - return 0; -} -RTM_EXPORT(pthread_barrierattr_init); - -int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, - int *pshared) -{ - if (!attr) - return EINVAL; - *pshared = (int)*attr; - - return 0; -} -RTM_EXPORT(pthread_barrierattr_getpshared); - -int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) -{ - if (!attr) - return EINVAL; - if (pshared == PTHREAD_PROCESS_PRIVATE) - attr = PTHREAD_PROCESS_PRIVATE; - - return EINVAL; -} -RTM_EXPORT(pthread_barrierattr_setpshared); - -int pthread_barrier_destroy(pthread_barrier_t *barrier) -{ - rt_err_t result; - - if (!barrier) - return EINVAL; - - result = pthread_cond_destroy(&(barrier->cond)); - - return result; -} -RTM_EXPORT(pthread_barrier_destroy); - -int pthread_barrier_init(pthread_barrier_t *barrier, - const pthread_barrierattr_t *attr, - unsigned count) -{ - if (!barrier) - return EINVAL; - if (attr && (*attr != PTHREAD_PROCESS_PRIVATE)) - return EINVAL; - - barrier->count = count; - pthread_cond_init(&(barrier->cond), NULL); - pthread_mutex_init(&(barrier->mutex), NULL); - - return 0; -} -RTM_EXPORT(pthread_barrier_init); - -int pthread_barrier_wait(pthread_barrier_t *barrier) -{ - rt_err_t result; - if (!barrier) - return EINVAL; - - result = pthread_mutex_lock(&(barrier->mutex)); - if (result != 0) - return EINVAL; - - if (barrier->count == 0) - result = EINVAL; - else - { - barrier->count -= 1; - if (barrier->count == 0) /* broadcast condition */ - pthread_cond_broadcast(&(barrier->cond)); - else - pthread_cond_wait(&(barrier->cond), &(barrier->mutex)); - } - - pthread_mutex_unlock(&(barrier->mutex)); - - return result; -} -RTM_EXPORT(pthread_barrier_wait); - diff --git a/components/libc/pthreads/pthread_cond.c b/components/libc/pthreads/pthread_cond.c deleted file mode 100644 index 9bf49704ed..0000000000 --- a/components/libc/pthreads/pthread_cond.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#include -#include "pthread_internal.h" - -int pthread_condattr_destroy(pthread_condattr_t *attr) -{ - if (!attr) - return EINVAL; - - return 0; -} -RTM_EXPORT(pthread_condattr_destroy); - -int pthread_condattr_init(pthread_condattr_t *attr) -{ - if (!attr) - return EINVAL; - *attr = PTHREAD_PROCESS_PRIVATE; - - return 0; -} -RTM_EXPORT(pthread_condattr_init); - -int pthread_condattr_getclock(const pthread_condattr_t *attr, - clockid_t *clock_id) -{ - return 0; -} -RTM_EXPORT(pthread_condattr_getclock); - -int pthread_condattr_setclock(pthread_condattr_t *attr, - clockid_t clock_id) -{ - return 0; -} -RTM_EXPORT(pthread_condattr_setclock); - -int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared) -{ - if (!attr || !pshared) - return EINVAL; - - *pshared = PTHREAD_PROCESS_PRIVATE; - - return 0; -} -RTM_EXPORT(pthread_condattr_getpshared); - -int pthread_condattr_setpshared(pthread_condattr_t*attr, int pshared) -{ - if ((pshared != PTHREAD_PROCESS_PRIVATE) && - (pshared != PTHREAD_PROCESS_SHARED)) - { - return EINVAL; - } - - if (pshared != PTHREAD_PROCESS_PRIVATE) - return ENOSYS; - - return 0; -} -RTM_EXPORT(pthread_condattr_setpshared); - -int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) -{ - rt_err_t result; - char cond_name[RT_NAME_MAX]; - static rt_uint16_t cond_num = 0; - - /* parameter check */ - if (cond == RT_NULL) - return EINVAL; - if ((attr != RT_NULL) && (*attr != PTHREAD_PROCESS_PRIVATE)) - return EINVAL; - - rt_snprintf(cond_name, sizeof(cond_name), "cond%02d", cond_num++); - - if (attr == RT_NULL) /* use default value */ - cond->attr = PTHREAD_PROCESS_PRIVATE; - else - cond->attr = *attr; - - result = rt_sem_init(&cond->sem, cond_name, 0, RT_IPC_FLAG_FIFO); - if (result != RT_EOK) - return EINVAL; - - /* detach the object from system object container */ - rt_object_detach(&(cond->sem.parent.parent)); - cond->sem.parent.parent.type = RT_Object_Class_Semaphore; - - return 0; -} -RTM_EXPORT(pthread_cond_init); - -int pthread_cond_destroy(pthread_cond_t *cond) -{ - rt_err_t result; - if (cond == RT_NULL) - return EINVAL; - if (cond->attr == -1) - return 0; /* which is not initialized */ - - result = rt_sem_trytake(&(cond->sem)); - if (result != RT_EOK) - return EBUSY; - - /* clean condition */ - rt_memset(cond, 0, sizeof(pthread_cond_t)); - cond->attr = -1; - - return 0; -} -RTM_EXPORT(pthread_cond_destroy); - -int pthread_cond_broadcast(pthread_cond_t *cond) -{ - rt_err_t result; - - if (cond == RT_NULL) - return EINVAL; - if (cond->attr == -1) - pthread_cond_init(cond, RT_NULL); - - rt_enter_critical(); - while (1) - { - /* try to take condition semaphore */ - result = rt_sem_trytake(&(cond->sem)); - if (result == -RT_ETIMEOUT) - { - /* it's timeout, release this semaphore */ - rt_sem_release(&(cond->sem)); - } - else if (result == RT_EOK) - { - /* has taken this semaphore, release it */ - rt_sem_release(&(cond->sem)); - break; - } - else - { - rt_exit_critical(); - - return EINVAL; - } - } - rt_exit_critical(); - - return 0; -} -RTM_EXPORT(pthread_cond_broadcast); - -int pthread_cond_signal(pthread_cond_t *cond) -{ - rt_err_t result; - - if (cond == RT_NULL) - return EINVAL; - if (cond->attr == -1) - pthread_cond_init(cond, RT_NULL); - - result = rt_sem_release(&(cond->sem)); - if (result == RT_EOK) - return 0; - - return 0; -} -RTM_EXPORT(pthread_cond_signal); - -rt_err_t _pthread_cond_timedwait(pthread_cond_t *cond, - pthread_mutex_t *mutex, - rt_int32_t timeout) -{ - rt_err_t result; - - if (!cond || !mutex) - return -RT_ERROR; - /* check whether initialized */ - if (cond->attr == -1) - pthread_cond_init(cond, RT_NULL); - - /* The mutex was not owned by the current thread at the time of the call. */ - if (mutex->lock.owner != rt_thread_self()) - return -RT_ERROR; - /* unlock a mutex failed */ - if (pthread_mutex_unlock(mutex) != 0) - return -RT_ERROR; - - result = rt_sem_take(&(cond->sem), timeout); - /* lock mutex again */ - pthread_mutex_lock(mutex); - - return result; -} -RTM_EXPORT(_pthread_cond_timedwait); - -int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - rt_err_t result; - - result = _pthread_cond_timedwait(cond, mutex, RT_WAITING_FOREVER); - if (result == RT_EOK) - return 0; - - return EINVAL; -} -RTM_EXPORT(pthread_cond_wait); - -int pthread_cond_timedwait(pthread_cond_t *cond, - pthread_mutex_t *mutex, - const struct timespec *abstime) -{ - int timeout; - rt_err_t result; - - timeout = rt_timespec_to_tick(abstime); - result = _pthread_cond_timedwait(cond, mutex, timeout); - if (result == RT_EOK) - return 0; - if (result == -RT_ETIMEOUT) - return ETIMEDOUT; - - return EINVAL; -} -RTM_EXPORT(pthread_cond_timedwait); - diff --git a/components/libc/pthreads/pthread_internal.h b/components/libc/pthreads/pthread_internal.h deleted file mode 100644 index 1fce29f636..0000000000 --- a/components/libc/pthreads/pthread_internal.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#ifndef __PTHREAD_INTERNAL_H__ -#define __PTHREAD_INTERNAL_H__ - -#include -#include -#include - -struct _pthread_cleanup -{ - void (*cleanup_func)(void *parameter); - void *parameter; - - struct _pthread_cleanup *next; -}; -typedef struct _pthread_cleanup _pthread_cleanup_t; - -struct _pthread_key_data -{ - int is_used; - void (*destructor)(void *parameter); -}; -typedef struct _pthread_key_data _pthread_key_data_t; - -#ifndef PTHREAD_NUM_MAX -#define PTHREAD_NUM_MAX 32 -#endif - -#define PTHREAD_MAGIC 0x70746873 -struct _pthread_data -{ - rt_uint32_t magic; - pthread_attr_t attr; - rt_thread_t tid; - - void* (*thread_entry)(void *parameter); - void *thread_parameter; - - /* return value */ - void *return_value; - - /* semaphore for joinable thread */ - rt_sem_t joinable_sem; - - /* cancel state and type */ - rt_uint8_t cancelstate; - volatile rt_uint8_t canceltype; - volatile rt_uint8_t canceled; - - _pthread_cleanup_t *cleanup; - void** tls; /* thread-local storage area */ -}; -typedef struct _pthread_data _pthread_data_t; - -_pthread_data_t *_pthread_get_data(pthread_t thread); - -void posix_mq_system_init(void); -void posix_sem_system_init(void); -void pthread_key_system_init(void); - -#endif diff --git a/components/libc/pthreads/pthread_mutex.c b/components/libc/pthreads/pthread_mutex.c deleted file mode 100644 index a681380b11..0000000000 --- a/components/libc/pthreads/pthread_mutex.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#include -#include "pthread.h" - -#define MUTEXATTR_SHARED_MASK 0x0010 -#define MUTEXATTR_TYPE_MASK 0x000f - -const pthread_mutexattr_t pthread_default_mutexattr = PTHREAD_PROCESS_PRIVATE; - -int pthread_mutexattr_init(pthread_mutexattr_t *attr) -{ - if (attr) - { - *attr = pthread_default_mutexattr; - - return 0; - } - - return EINVAL; -} -RTM_EXPORT(pthread_mutexattr_init); - -int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) -{ - if (attr) - { - *attr = -1; - - return 0; - } - - return EINVAL; -} -RTM_EXPORT(pthread_mutexattr_destroy); - -int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) -{ - if (attr && type) - { - int atype = (*attr & MUTEXATTR_TYPE_MASK); - - if (atype >= PTHREAD_MUTEX_NORMAL && atype <= PTHREAD_MUTEX_ERRORCHECK) - { - *type = atype; - - return 0; - } - } - - return EINVAL; -} -RTM_EXPORT(pthread_mutexattr_gettype); - -int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) -{ - if (attr && type >= PTHREAD_MUTEX_NORMAL && type <= PTHREAD_MUTEX_ERRORCHECK) - { - *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type; - - return 0; - } - - return EINVAL; -} -RTM_EXPORT(pthread_mutexattr_settype); - -int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) -{ - if (!attr) - return EINVAL; - - switch (pshared) - { - case PTHREAD_PROCESS_PRIVATE: - *attr &= ~MUTEXATTR_SHARED_MASK; - return 0; - - case PTHREAD_PROCESS_SHARED: - *attr |= MUTEXATTR_SHARED_MASK; - return 0; - } - - return EINVAL; -} -RTM_EXPORT(pthread_mutexattr_setpshared); - -int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared) -{ - if (!attr || !pshared) - return EINVAL; - - *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED - : PTHREAD_PROCESS_PRIVATE; - return 0; -} -RTM_EXPORT(pthread_mutexattr_getpshared); - -int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) -{ - rt_err_t result; - char name[RT_NAME_MAX]; - static rt_uint16_t pthread_mutex_number = 0; - - if (!mutex) - return EINVAL; - - /* build mutex name */ - rt_snprintf(name, sizeof(name), "pmtx%02d", pthread_mutex_number ++); - if (attr == RT_NULL) - mutex->attr = pthread_default_mutexattr; - else - mutex->attr = *attr; - - /* init mutex lock */ - result = rt_mutex_init(&(mutex->lock), name, RT_IPC_FLAG_FIFO); - if (result != RT_EOK) - return EINVAL; - - /* detach the object from system object container */ - rt_object_detach(&(mutex->lock.parent.parent)); - mutex->lock.parent.parent.type = RT_Object_Class_Mutex; - - return 0; -} -RTM_EXPORT(pthread_mutex_init); - -int pthread_mutex_destroy(pthread_mutex_t *mutex) -{ - if (!mutex || mutex->attr == -1) - return EINVAL; - - /* it's busy */ - if (mutex->lock.owner != RT_NULL) - return EBUSY; - - rt_memset(mutex, 0, sizeof(pthread_mutex_t)); - mutex->attr = -1; - - return 0; -} -RTM_EXPORT(pthread_mutex_destroy); - -int pthread_mutex_lock(pthread_mutex_t *mutex) -{ - int mtype; - rt_err_t result; - - if (!mutex) - return EINVAL; - - if (mutex->attr == -1) - { - /* init mutex */ - pthread_mutex_init(mutex, RT_NULL); - } - - mtype = mutex->attr & MUTEXATTR_TYPE_MASK; - rt_enter_critical(); - if (mutex->lock.owner == rt_thread_self() && - mtype != PTHREAD_MUTEX_RECURSIVE) - { - rt_exit_critical(); - - return EDEADLK; - } - rt_exit_critical(); - - result = rt_mutex_take(&(mutex->lock), RT_WAITING_FOREVER); - if (result == RT_EOK) - return 0; - - return EINVAL; -} -RTM_EXPORT(pthread_mutex_lock); - -int pthread_mutex_unlock(pthread_mutex_t *mutex) -{ - rt_err_t result; - - if (!mutex) - return EINVAL; - if (mutex->attr == -1) - { - /* init mutex */ - pthread_mutex_init(mutex, RT_NULL); - } - - if (mutex->lock.owner != rt_thread_self()) - { - int mtype; - mtype = mutex->attr & MUTEXATTR_TYPE_MASK; - - /* error check, return EPERM */ - if (mtype == PTHREAD_MUTEX_ERRORCHECK) - return EPERM; - - /* no thread waiting on this mutex */ - if (mutex->lock.owner == RT_NULL) - return 0; - } - - result = rt_mutex_release(&(mutex->lock)); - if (result == RT_EOK) - return 0; - - return EINVAL; -} -RTM_EXPORT(pthread_mutex_unlock); - -int pthread_mutex_trylock(pthread_mutex_t *mutex) -{ - rt_err_t result; - int mtype; - - if (!mutex) - return EINVAL; - if (mutex->attr == -1) - { - /* init mutex */ - pthread_mutex_init(mutex, RT_NULL); - } - - mtype = mutex->attr & MUTEXATTR_TYPE_MASK; - rt_enter_critical(); - if (mutex->lock.owner == rt_thread_self() && - mtype != PTHREAD_MUTEX_RECURSIVE) - { - rt_exit_critical(); - - return EDEADLK; - } - rt_exit_critical(); - - result = rt_mutex_take(&(mutex->lock), 0); - if (result == RT_EOK) return 0; - - return EBUSY; -} -RTM_EXPORT(pthread_mutex_trylock); diff --git a/components/libc/pthreads/pthread_rwlock.c b/components/libc/pthreads/pthread_rwlock.c deleted file mode 100644 index 1c2fe19f5f..0000000000 --- a/components/libc/pthreads/pthread_rwlock.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#include - -int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) -{ - if (!attr) - return EINVAL; - *attr = PTHREAD_PROCESS_PRIVATE; - - return 0; -} -RTM_EXPORT(pthread_rwlockattr_init); - -int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) -{ - if (!attr) - return EINVAL; - - return 0; -} -RTM_EXPORT(pthread_rwlockattr_destroy); - -int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, - int *pshared) -{ - if (!attr || !pshared) - return EINVAL; - - *pshared = PTHREAD_PROCESS_PRIVATE; - - return 0; -} -RTM_EXPORT(pthread_rwlockattr_getpshared); - -int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) -{ - if (!attr || pshared != PTHREAD_PROCESS_PRIVATE) - return EINVAL; - - return 0; -} -RTM_EXPORT(pthread_rwlockattr_setpshared); - -int pthread_rwlock_init(pthread_rwlock_t *rwlock, - const pthread_rwlockattr_t *attr) -{ - if (!rwlock) - return EINVAL; - - rwlock->attr = PTHREAD_PROCESS_PRIVATE; - pthread_mutex_init(&(rwlock->rw_mutex), NULL); - pthread_cond_init(&(rwlock->rw_condreaders), NULL); - pthread_cond_init(&(rwlock->rw_condwriters), NULL); - - rwlock->rw_nwaitwriters = 0; - rwlock->rw_nwaitreaders = 0; - rwlock->rw_refcount = 0; - - return 0; -} -RTM_EXPORT(pthread_rwlock_init); - -int pthread_rwlock_destroy (pthread_rwlock_t *rwlock) -{ - int result; - - if (!rwlock) - return EINVAL; - if (rwlock->attr == -1) - return 0; /* rwlock is not initialized */ - - if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) - return(result); - - if (rwlock->rw_refcount != 0 || - rwlock->rw_nwaitreaders != 0 || - rwlock->rw_nwaitwriters != 0) - { - result = EBUSY; - - return result; - } - else - { - /* check whether busy */ - result = rt_sem_trytake(&(rwlock->rw_condreaders.sem)); - if (result == RT_EOK) - { - result = rt_sem_trytake(&(rwlock->rw_condwriters.sem)); - if (result == RT_EOK) - { - rt_sem_release(&(rwlock->rw_condreaders.sem)); - rt_sem_release(&(rwlock->rw_condwriters.sem)); - - pthread_cond_destroy(&rwlock->rw_condreaders); - pthread_cond_destroy(&rwlock->rw_condwriters); - } - else - { - rt_sem_release(&(rwlock->rw_condreaders.sem)); - result = EBUSY; - } - } - else - result = EBUSY; - } - - pthread_mutex_unlock(&rwlock->rw_mutex); - if (result == 0) - pthread_mutex_destroy(&rwlock->rw_mutex); - - return result; -} -RTM_EXPORT(pthread_rwlock_destroy); - -int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) -{ - int result; - - if (!rwlock) - return EINVAL; - if (rwlock->attr == -1) - pthread_rwlock_init(rwlock, NULL); - - if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) - return(result); - - /* give preference to waiting writers */ - while (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) - { - rwlock->rw_nwaitreaders++; - /* rw_mutex will be released when waiting for rw_condreaders */ - result = pthread_cond_wait(&rwlock->rw_condreaders, &rwlock->rw_mutex); - /* rw_mutex should have been taken again when returned from waiting */ - rwlock->rw_nwaitreaders--; - if (result != 0) /* wait error */ - break; - } - - /* another reader has a read lock */ - if (result == 0) - rwlock->rw_refcount++; - - pthread_mutex_unlock(&rwlock->rw_mutex); - - return (result); -} -RTM_EXPORT(pthread_rwlock_rdlock); - -int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) -{ - int result; - - if (!rwlock) - return EINVAL; - if (rwlock->attr == -1) - pthread_rwlock_init(rwlock, NULL); - - if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) - return(result); - - if (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) - result = EBUSY; /* held by a writer or waiting writers */ - else - rwlock->rw_refcount++; /* increment count of reader locks */ - - pthread_mutex_unlock(&rwlock->rw_mutex); - - return(result); -} -RTM_EXPORT(pthread_rwlock_tryrdlock); - -int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, - const struct timespec *abstime) -{ - int result; - - if (!rwlock) - return EINVAL; - if (rwlock->attr == -1) - pthread_rwlock_init(rwlock, NULL); - - if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) - return(result); - - /* give preference to waiting writers */ - while (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) - { - rwlock->rw_nwaitreaders++; - /* rw_mutex will be released when waiting for rw_condreaders */ - result = pthread_cond_timedwait(&rwlock->rw_condreaders, &rwlock->rw_mutex, abstime); - /* rw_mutex should have been taken again when returned from waiting */ - rwlock->rw_nwaitreaders--; - if (result != 0) - break; - } - - /* another reader has a read lock */ - if (result == 0) - rwlock->rw_refcount++; - - pthread_mutex_unlock(&rwlock->rw_mutex); - - return (result); -} -RTM_EXPORT(pthread_rwlock_timedrdlock); - -int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, - const struct timespec *abstime) -{ - int result; - - if (!rwlock) - return EINVAL; - if (rwlock->attr == -1) - pthread_rwlock_init(rwlock, NULL); - - if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) - return(result); - - while (rwlock->rw_refcount != 0) - { - rwlock->rw_nwaitwriters++; - /* rw_mutex will be released when waiting for rw_condwriters */ - result = pthread_cond_timedwait(&rwlock->rw_condwriters, &rwlock->rw_mutex, abstime); - /* rw_mutex should have been taken again when returned from waiting */ - rwlock->rw_nwaitwriters--; - - if (result != 0) - break; - } - - if (result == 0) - rwlock->rw_refcount = -1; - - pthread_mutex_unlock(&rwlock->rw_mutex); - - return(result); -} -RTM_EXPORT(pthread_rwlock_timedwrlock); - -int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) -{ - int result; - - if (!rwlock) - return EINVAL; - if (rwlock->attr == -1) - pthread_rwlock_init(rwlock, NULL); - - if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) - return(result); - - if (rwlock->rw_refcount != 0) - result = EBUSY; /* held by either writer or reader(s) */ - else - rwlock->rw_refcount = -1; /* available, indicate a writer has it */ - - pthread_mutex_unlock(&rwlock->rw_mutex); - - return(result); -} -RTM_EXPORT(pthread_rwlock_trywrlock); - -int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) -{ - int result; - - if (!rwlock) - return EINVAL; - if (rwlock->attr == -1) - pthread_rwlock_init(rwlock, NULL); - - if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) - return(result); - - if (rwlock->rw_refcount > 0) - rwlock->rw_refcount--; /* releasing a reader */ - else if (rwlock->rw_refcount == -1) - rwlock->rw_refcount = 0; /* releasing a writer */ - - /* give preference to waiting writers over waiting readers */ - if (rwlock->rw_nwaitwriters > 0) - { - if (rwlock->rw_refcount == 0) - result = pthread_cond_signal(&rwlock->rw_condwriters); - } - else if (rwlock->rw_nwaitreaders > 0) - { - result = pthread_cond_broadcast(&rwlock->rw_condreaders); - } - - pthread_mutex_unlock(&rwlock->rw_mutex); - - return(result); -} -RTM_EXPORT(pthread_rwlock_unlock); - -int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) -{ - int result; - - if (!rwlock) - return EINVAL; - if (rwlock->attr == -1) - pthread_rwlock_init(rwlock, NULL); - - if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) - return(result); - - while (rwlock->rw_refcount != 0) - { - rwlock->rw_nwaitwriters++; - /* rw_mutex will be released when waiting for rw_condwriters */ - result = pthread_cond_wait(&rwlock->rw_condwriters, &rwlock->rw_mutex); - /* rw_mutex should have been taken again when returned from waiting */ - rwlock->rw_nwaitwriters--; - - if (result != 0) - break; - } - - if (result == 0) - rwlock->rw_refcount = -1; - - pthread_mutex_unlock(&rwlock->rw_mutex); - - return(result); -} -RTM_EXPORT(pthread_rwlock_wrlock); - diff --git a/components/libc/pthreads/pthread_spin.c b/components/libc/pthreads/pthread_spin.c deleted file mode 100644 index 3f3dc1593c..0000000000 --- a/components/libc/pthreads/pthread_spin.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#include - -int pthread_spin_init (pthread_spinlock_t *lock, int pshared) -{ - if (!lock) - return EINVAL; - - lock->lock = 0; - - return 0; -} - -int pthread_spin_destroy (pthread_spinlock_t *lock) -{ - if (!lock) - return EINVAL; - - return 0; -} - -int pthread_spin_lock (pthread_spinlock_t *lock) -{ - if (!lock) - return EINVAL; - - while (!(lock->lock)) - { - lock->lock = 1; - } - - return 0; -} - -int pthread_spin_trylock (pthread_spinlock_t *lock) -{ - if (!lock) - return EINVAL; - - if (!(lock->lock)) - { - lock->lock = 1; - - return 0; - } - - return EBUSY; -} - -int pthread_spin_unlock (pthread_spinlock_t *lock) -{ - if (!lock) - return EINVAL; - if (!(lock->lock)) - return EPERM; - - lock->lock = 0; - - return 0; -} diff --git a/components/libc/pthreads/pthread_tls.c b/components/libc/pthreads/pthread_tls.c deleted file mode 100644 index d48df7f2dd..0000000000 --- a/components/libc/pthreads/pthread_tls.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#include -#include "pthread_internal.h" - -_pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; - -void pthread_key_system_init() -{ - rt_memset(&_thread_keys[0], 0, sizeof(_thread_keys)); -} - -void *pthread_getspecific(pthread_key_t key) -{ - struct _pthread_data* ptd; - - if (rt_thread_self() == NULL) return NULL; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - RT_ASSERT(ptd != NULL); - - if (ptd->tls == NULL) - return NULL; - - if ((key < PTHREAD_KEY_MAX) && (_thread_keys[key].is_used)) - return ptd->tls[key]; - - return NULL; -} -RTM_EXPORT(pthread_getspecific); - -int pthread_setspecific(pthread_key_t key, const void *value) -{ - struct _pthread_data* ptd; - - if (rt_thread_self() == NULL) return EINVAL; - - /* get pthread data from user data of thread */ - ptd = (_pthread_data_t *)rt_thread_self()->user_data; - RT_ASSERT(ptd != NULL); - - /* check tls area */ - if (ptd->tls == NULL) - { - ptd->tls = (void**)rt_malloc(sizeof(void*) * PTHREAD_KEY_MAX); - } - - if ((key < PTHREAD_KEY_MAX) && _thread_keys[key].is_used) - { - ptd->tls[key] = (void *)value; - - return 0; - } - - return EINVAL; -} -RTM_EXPORT(pthread_setspecific); - -int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) -{ - rt_uint32_t index; - - rt_enter_critical(); - for (index = 0; index < PTHREAD_KEY_MAX; index ++) - { - if (_thread_keys[index].is_used == 0) - { - _thread_keys[index].is_used = 1; - _thread_keys[index].destructor = destructor; - - *key = index; - - rt_exit_critical(); - - return 0; - } - } - - rt_exit_critical(); - - return EAGAIN; -} -RTM_EXPORT(pthread_key_create); - -int pthread_key_delete(pthread_key_t key) -{ - if (key >= PTHREAD_KEY_MAX) - return EINVAL; - - rt_enter_critical(); - _thread_keys[key].is_used = 0; - _thread_keys[key].destructor = 0; - rt_exit_critical(); - - return 0; -} -RTM_EXPORT(pthread_key_delete); - diff --git a/components/libc/pthreads/sched.c b/components/libc/pthreads/sched.c deleted file mode 100644 index 5f2a53c01f..0000000000 --- a/components/libc/pthreads/sched.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - */ - -#include - -int sched_yield(void) -{ - rt_thread_yield(); - - return 0; -} -RTM_EXPORT(sched_yield); - -int sched_get_priority_min(int policy) -{ - if (policy != SCHED_FIFO && policy != SCHED_RR) - return EINVAL; - - return 0; -} -RTM_EXPORT(sched_get_priority_min); - -int sched_get_priority_max(int policy) -{ - if (policy != SCHED_FIFO && policy != SCHED_RR) - return EINVAL; - - return RT_THREAD_PRIORITY_MAX - 1; -} -RTM_EXPORT(sched_get_priority_max); - -int sched_setscheduler(pid_t pid, int policy) -{ - return EOPNOTSUPP; -} -RTM_EXPORT(sched_setscheduler); diff --git a/components/libc/pthreads/sched.h b/components/libc/pthreads/sched.h deleted file mode 100644 index 07e2c0c6a8..0000000000 --- a/components/libc/pthreads/sched.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - */ - -#ifndef __SCHED_H__ -#define __SCHED_H__ - -#include -#include - -/* Thread scheduling policies */ -enum -{ - SCHED_OTHER = 0, - SCHED_FIFO, - SCHED_RR, - SCHED_MIN = SCHED_OTHER, - SCHED_MAX = SCHED_RR -}; - -#ifdef __cplusplus -extern "C" -{ -#endif - -int sched_yield(void); -int sched_get_priority_min(int policy); -int sched_get_priority_max(int policy); -int sched_setscheduler(pid_t pid, int policy); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/libc/pthreads/semaphore.c b/components/libc/pthreads/semaphore.c deleted file mode 100644 index 5e59ae850f..0000000000 --- a/components/libc/pthreads/semaphore.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#include -#include -#include "semaphore.h" -#include "pthread_internal.h" - -static sem_t *posix_sem_list = RT_NULL; -static struct rt_semaphore posix_sem_lock; -void posix_sem_system_init() -{ - rt_sem_init(&posix_sem_lock, "psem", 1, RT_IPC_FLAG_FIFO); -} - -rt_inline void posix_sem_insert(sem_t *psem) -{ - psem->next = posix_sem_list; - posix_sem_list = psem; -} - -static void posix_sem_delete(sem_t *psem) -{ - sem_t *iter; - if (posix_sem_list == psem) - { - posix_sem_list = psem->next; - - rt_sem_delete(psem->sem); - rt_free(psem); - - return; - } - for (iter = posix_sem_list; iter->next != RT_NULL; iter = iter->next) - { - if (iter->next == psem) - { - /* delete this mq */ - if (psem->next != RT_NULL) - iter->next = psem->next; - else - iter->next = RT_NULL; - - /* delete RT-Thread mqueue */ - rt_sem_delete(psem->sem); - rt_free(psem); - - return ; - } - } -} - -static sem_t *posix_sem_find(const char* name) -{ - sem_t *iter; - rt_object_t object; - - for (iter = posix_sem_list; iter != RT_NULL; iter = iter->next) - { - object = (rt_object_t)iter->sem; - - if (strncmp(object->name, name, RT_NAME_MAX) == 0) - { - return iter; - } - } - - return RT_NULL; -} - -int sem_close(sem_t *sem) -{ - if (sem == RT_NULL) - { - rt_set_errno(EINVAL); - - return -1; - } - - /* lock posix semaphore list */ - rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); - sem->refcount --; - if (sem->refcount == 0) - { - /* delete from posix semaphore list */ - if (sem->unlinked) - posix_sem_delete(sem); - sem = RT_NULL; - } - rt_sem_release(&posix_sem_lock); - - return 0; -} -RTM_EXPORT(sem_close); - -int sem_destroy(sem_t *sem) -{ - rt_err_t result; - - if ((!sem) || !(sem->unamed)) - { - rt_set_errno(EINVAL); - - return -1; - } - - /* lock posix semaphore list */ - rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); - result = rt_sem_trytake(sem->sem); - if (result != RT_EOK) - { - rt_sem_release(&posix_sem_lock); - rt_set_errno(EBUSY); - - return -1; - } - - /* destroy an unamed posix semaphore */ - posix_sem_delete(sem); - rt_sem_release(&posix_sem_lock); - - return 0; -} -RTM_EXPORT(sem_destroy); - -int sem_unlink(const char *name) -{ - sem_t *psem; - - /* lock posix semaphore list */ - rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); - psem = posix_sem_find(name); - if (psem != RT_NULL) - { - psem->unlinked = 1; - if (psem->refcount == 0) - { - /* remove this semaphore */ - posix_sem_delete(psem); - } - rt_sem_release(&posix_sem_lock); - - return 0; - } - rt_sem_release(&posix_sem_lock); - - /* no this entry */ - rt_set_errno(ENOENT); - - return -1; -} -RTM_EXPORT(sem_unlink); - -int sem_getvalue(sem_t *sem, int *sval) -{ - if (!sem || !sval) - { - rt_set_errno(EINVAL); - - return -1; - } - *sval = sem->sem->value; - - return 0; -} -RTM_EXPORT(sem_getvalue); - -int sem_init(sem_t *sem, int pshared, unsigned int value) -{ - char name[RT_NAME_MAX]; - static rt_uint16_t psem_number = 0; - - if (sem == RT_NULL) - { - rt_set_errno(EINVAL); - - return -1; - } - - rt_snprintf(name, sizeof(name), "psem%02d", psem_number++); - sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO); - if (sem->sem == RT_NULL) - { - rt_set_errno(ENOMEM); - - return -1; - } - - /* initialize posix semaphore */ - sem->refcount = 1; - sem->unlinked = 0; - sem->unamed = 1; - /* lock posix semaphore list */ - rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); - posix_sem_insert(sem); - rt_sem_release(&posix_sem_lock); - - return 0; -} -RTM_EXPORT(sem_init); - -sem_t *sem_open(const char *name, int oflag, ...) -{ - sem_t* sem; - va_list arg; - mode_t mode; - unsigned int value; - - sem = RT_NULL; - - /* lock posix semaphore list */ - rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); - if (oflag & O_CREAT) - { - va_start(arg, oflag); - mode = (mode_t) va_arg( arg, unsigned int); mode = mode; - value = va_arg( arg, unsigned int); - va_end(arg); - - if (oflag & O_EXCL) - { - if (posix_sem_find(name) != RT_NULL) - { - rt_set_errno(EEXIST); - goto __return; - } - } - sem = (sem_t*) rt_malloc (sizeof(struct posix_sem)); - if (sem == RT_NULL) - { - rt_set_errno(ENFILE); - goto __return; - } - - /* create RT-Thread semaphore */ - sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO); - if (sem->sem == RT_NULL) /* create failed */ - { - rt_set_errno(ENFILE); - goto __return; - } - /* initialize reference count */ - sem->refcount = 1; - sem->unlinked = 0; - sem->unamed = 0; - - /* insert semaphore to posix semaphore list */ - posix_sem_insert(sem); - } - else - { - /* find semaphore */ - sem = posix_sem_find(name); - if (sem != RT_NULL) - { - sem->refcount ++; /* increase reference count */ - } - else - { - rt_set_errno(ENOENT); - goto __return; - } - } - rt_sem_release(&posix_sem_lock); - - return sem; - -__return: - /* release lock */ - rt_sem_release(&posix_sem_lock); - - /* release allocated memory */ - if (sem != RT_NULL) - { - /* delete RT-Thread semaphore */ - if (sem->sem != RT_NULL) - rt_sem_delete(sem->sem); - rt_free(sem); - } - - return RT_NULL; -} -RTM_EXPORT(sem_open); - -int sem_post(sem_t *sem) -{ - rt_err_t result; - - if (!sem) - { - rt_set_errno(EINVAL); - - return -1; - } - - result = rt_sem_release(sem->sem); - if (result == RT_EOK) - return 0; - - rt_set_errno(EINVAL); - - return -1; -} -RTM_EXPORT(sem_post); - -int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout) -{ - rt_err_t result; - rt_int32_t tick; - - if (!sem || !abs_timeout) - return EINVAL; - - /* calculate os tick */ - tick = rt_timespec_to_tick(abs_timeout); - - result = rt_sem_take(sem->sem, tick); - if (result == -RT_ETIMEOUT) - { - rt_set_errno(ETIMEDOUT); - - return -1; - } - if (result == RT_EOK) - return 0; - - rt_set_errno(EINTR); - - return -1; -} -RTM_EXPORT(sem_timedwait); - -int sem_trywait(sem_t *sem) -{ - rt_err_t result; - - if (!sem) - { - rt_set_errno(EINVAL); - - return -1; - } - - result = rt_sem_take(sem->sem, 0); - if (result == -RT_ETIMEOUT) - { - rt_set_errno(EAGAIN); - - return -1; - } - if (result == RT_EOK) - return 0; - - rt_set_errno(EINTR); - - return -1; -} -RTM_EXPORT(sem_trywait); - -int sem_wait(sem_t *sem) -{ - rt_err_t result; - - if (!sem) - { - rt_set_errno(EINVAL); - - return -1; - } - - result = rt_sem_take(sem->sem, RT_WAITING_FOREVER); - if (result == RT_EOK) - return 0; - - rt_set_errno(EINTR); - - return -1; -} -RTM_EXPORT(sem_wait); - diff --git a/components/libc/pthreads/semaphore.h b/components/libc/pthreads/semaphore.h deleted file mode 100644 index 872226e385..0000000000 --- a/components/libc/pthreads/semaphore.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2010-10-26 Bernard the first version - */ - -#ifndef __POSIX_SEMAPHORE_H__ -#define __POSIX_SEMAPHORE_H__ - -#include -#include - -struct posix_sem -{ - /* reference count and unlinked */ - rt_uint16_t refcount; - rt_uint8_t unlinked; - rt_uint8_t unamed; - - /* RT-Thread semaphore */ - rt_sem_t sem; - - /* next posix semaphore */ - struct posix_sem* next; -}; -typedef struct posix_sem sem_t; - -int sem_close(sem_t *sem); -int sem_destroy(sem_t *sem); -int sem_getvalue(sem_t *sem, int *sval); -int sem_init(sem_t *sem, int pshared, unsigned int value); -sem_t *sem_open(const char *name, int oflag, ...); -int sem_post(sem_t *sem); -int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); -int sem_trywait(sem_t *sem); -int sem_unlink(const char *name); -int sem_wait(sem_t *sem); - -#endif diff --git a/components/libc/signal/SConscript b/components/libc/signal/SConscript deleted file mode 100644 index f07ff58f6e..0000000000 --- a/components/libc/signal/SConscript +++ /dev/null @@ -1,13 +0,0 @@ -# RT-Thread building script for component - -from building import * - -cwd = GetCurrentDir() -src = Glob('*.c') + Glob('*.cpp') -CPPPATH = [cwd] - -group = DefineGroup('libc', src, - depend = ['RT_USING_SIGNALS', 'RT_USING_PTHREADS', 'RT_USING_LIBC'], - CPPPATH = CPPPATH) - -Return('group') diff --git a/components/libc/signal/posix_signal.c b/components/libc/signal/posix_signal.c deleted file mode 100644 index ac8d2b1eef..0000000000 --- a/components/libc/signal/posix_signal.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017/10/1 Bernard The first version - */ - -#include -#include - -#include -#include - -#include "posix_signal.h" - -#define sig_valid(sig_no) (sig_no >= 0 && sig_no < RT_SIG_MAX) - -void (*signal(int sig, void (*func)(int))) (int) -{ - return rt_signal_install(sig, func); -} - -int sigprocmask (int how, const sigset_t *set, sigset_t *oset) -{ - rt_base_t level; - rt_thread_t tid; - - tid = rt_thread_self(); - - level = rt_hw_interrupt_disable(); - if (oset) *oset = tid->sig_mask; - - if (set) - { - switch(how) - { - case SIG_BLOCK: - tid->sig_mask |= *set; - break; - case SIG_UNBLOCK: - tid->sig_mask &= ~*set; - break; - case SIG_SETMASK: - tid->sig_mask = *set; - break; - default: - break; - } - } - rt_hw_interrupt_enable(level); - - return 0; -} - -int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) -{ - rt_sighandler_t old = RT_NULL; - - if (!sig_valid(signum)) return -RT_ERROR; - - if (act) - old = rt_signal_install(signum, act->sa_handler); - else - { - old = rt_signal_install(signum, RT_NULL); - rt_signal_install(signum, old); - } - - if (oldact) - oldact->sa_handler = old; - - return 0; -} - -int sigtimedwait(const sigset_t *set, siginfo_t *info, - const struct timespec *timeout) -{ - int ret = 0; - int tick = RT_WAITING_FOREVER; - - if (timeout) - { - tick = rt_timespec_to_tick(timeout); - } - - ret = rt_signal_wait(set, info, tick); - if (ret == 0) return 0; - - errno = ret; - return -1; -} - -int sigwait(const sigset_t *set, int *sig) -{ - siginfo_t si; - if (sigtimedwait(set, &si, 0) < 0) - return -1; - - *sig = si.si_signo; - return 0; -} - -int sigwaitinfo(const sigset_t *set, siginfo_t *info) -{ - return sigtimedwait(set, info, NULL); -} - -int raise(int sig) -{ - rt_thread_kill(rt_thread_self(), sig); - return 0; -} - diff --git a/components/libc/signal/posix_signal.h b/components/libc/signal/posix_signal.h deleted file mode 100644 index f04b54c5f8..0000000000 --- a/components/libc/signal/posix_signal.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017/10/1 Bernard The first version - */ - -#ifndef POSIX_SIGNAL_H__ -#define POSIX_SIGNAL_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -enum rt_signal_value{ - SIG1 = SIGHUP, - SIG2 = SIGINT, - SIG3 = SIGQUIT, - SIG4 = SIGILL, - SIG5 = SIGTRAP, - SIG6 = SIGABRT, - SIG7 = SIGEMT, - SIG8 = SIGFPE, - SIG9 = SIGKILL, - SIG10 = SIGBUS, - SIG11 = SIGSEGV, - SIG12 = SIGSYS, - SIG13 = SIGPIPE, - SIG14 = SIGALRM, - SIG15 = SIGTERM, - SIG16 = SIGURG, - SIG17 = SIGSTOP, - SIG18 = SIGTSTP, - SIG19 = SIGCONT, - SIG20 = SIGCHLD, - SIG21 = SIGTTIN, - SIG22 = SIGTTOU, - SIG23 = SIGPOLL, - SIG24 = 24, // SIGXCPU, - SIG25 = 25, // SIGXFSZ, - SIG26 = 26, // SIGVTALRM, - SIG27 = 27, // SIGPROF, - SIG28 = SIGWINCH, - SIG29 = 29, // SIGLOST, - SIG30 = SIGUSR1, - SIG31 = SIGUSR2, - SIGRT_MIN = 27, // SIGRTMIN, - SIGRT_MAX = 31, // SIGRTMAX, - SIGMAX = NSIG, -}; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/libc/termios/SConscript b/components/libc/termios/SConscript deleted file mode 100644 index 381eb5ad8b..0000000000 --- a/components/libc/termios/SConscript +++ /dev/null @@ -1,13 +0,0 @@ -# RT-Thread building script for component - -from building import * - -cwd = GetCurrentDir() -src = Glob('*.c') + Glob('*.cpp') -CPPPATH = [cwd] - -group = DefineGroup('libc', src, - depend = ['RT_USING_LIBC', 'RT_USING_POSIX', 'RT_USING_POSIX_TERMIOS'], - CPPPATH = CPPPATH) - -Return('group') diff --git a/components/libc/termios/posix_termios.c b/components/libc/termios/posix_termios.c deleted file mode 100644 index 9f33c857e6..0000000000 --- a/components/libc/termios/posix_termios.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017/08/30 Bernard The first version - */ -#include -#include -#include -#include -#include - -int tcgetattr(int fd, struct termios *tio) -{ - /* Get the current serial port settings. */ - if (ioctl(fd, TCGETA, tio)) - return -1; - - return 0; -} - -int tcsetattr(int fd, int act, const struct termios *tio) -{ - switch (act) - { - case TCSANOW: - /* make the change immediately */ - return (ioctl(fd, TCSETA, (void*)tio)); - case TCSADRAIN: - /* - * Don't make the change until all currently written data - * has been transmitted. - */ - return (ioctl(fd, TCSETAW, (void*)tio)); - case TCSAFLUSH: - /* Don't make the change until all currently written data - * has been transmitted, at which point any received but - * unread data is also discarded. - */ - return (ioctl(fd, TCSETAF, (void*)tio)); - default: - errno = EINVAL; - return (-1); - } -} - -/** - * this function gets process group ID for session leader for controlling - * terminal - * - * @return always 0 - */ -pid_t tcgetsid(int fd) -{ - return 0; -} - -speed_t cfgetospeed(const struct termios *tio) -{ - return tio->c_cflag & CBAUD; -} - -speed_t cfgetispeed(const struct termios *tio) -{ - return cfgetospeed(tio); -} - -int cfsetospeed(struct termios *tio, speed_t speed) -{ - if (speed & ~CBAUD) - { - errno = EINVAL; - return -1; - } - - tio->c_cflag &= ~CBAUD; - tio->c_cflag |= speed; - return 0; -} - -int cfsetispeed(struct termios *tio, speed_t speed) -{ - return speed ? cfsetospeed(tio, speed) : 0; -} - -int tcsendbreak(int fd, int dur) -{ - /* nonzero duration is implementation-defined, so ignore it */ - return 0; -} - -int tcflush(int fd, int queue) -{ - return ioctl(fd, TCFLSH, (void*)queue); -} - -int tcflow(int fd, int action) -{ - return ioctl(fd, TCXONC, (void*)action); -} - -/** - * this function waits for transmission of output - */ -int tcdrain(int fd) -{ - return 0; -} - -#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) -void cfmakeraw(struct termios *t) -{ - t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); - t->c_oflag &= ~OPOST; - t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - t->c_cflag &= ~(CSIZE|PARENB); - t->c_cflag |= CS8; - t->c_cc[VMIN] = 1; - t->c_cc[VTIME] = 0; -} - -int cfsetspeed(struct termios *tio, speed_t speed) -{ - return cfsetospeed(tio, speed); -} -#endif diff --git a/components/libc/termios/posix_termios.h b/components/libc/termios/posix_termios.h deleted file mode 100644 index 6dc5531955..0000000000 --- a/components/libc/termios/posix_termios.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017/08/30 Bernard The first version - */ -#ifndef TERMIOS_H__ -#define TERMIOS_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef unsigned char cc_t; -typedef unsigned int speed_t; -typedef unsigned int tcflag_t; - -#define NCCS 32 - -struct termios { - tcflag_t c_iflag; - tcflag_t c_oflag; - tcflag_t c_cflag; - tcflag_t c_lflag; - cc_t c_line; - cc_t c_cc[NCCS]; - speed_t __c_ispeed; - speed_t __c_ospeed; -}; - -#define VINTR 0 -#define VQUIT 1 -#define VERASE 2 -#define VKILL 3 -#define VEOF 4 -#define VTIME 5 -#define VMIN 6 -#define VSWTC 7 -#define VSTART 8 -#define VSTOP 9 -#define VSUSP 10 -#define VEOL 11 -#define VREPRINT 12 -#define VDISCARD 13 -#define VWERASE 14 -#define VLNEXT 15 -#define VEOL2 16 - -#define IGNBRK 0000001 -#define BRKINT 0000002 -#define IGNPAR 0000004 -#define PARMRK 0000010 -#define INPCK 0000020 -#define ISTRIP 0000040 -#define INLCR 0000100 -#define IGNCR 0000200 -#define ICRNL 0000400 -#define IUCLC 0001000 -#define IXON 0002000 -#define IXANY 0004000 -#define IXOFF 0010000 -#define IMAXBEL 0020000 -#define IUTF8 0040000 - -#define OPOST 0000001 -#define OLCUC 0000002 -#define ONLCR 0000004 -#define OCRNL 0000010 -#define ONOCR 0000020 -#define ONLRET 0000040 -#define OFILL 0000100 -#define OFDEL 0000200 -#define NLDLY 0000400 -#define NL0 0000000 -#define NL1 0000400 -#define CRDLY 0003000 -#define CR0 0000000 -#define CR1 0001000 -#define CR2 0002000 -#define CR3 0003000 -#define TABDLY 0014000 -#define TAB0 0000000 -#define TAB1 0004000 -#define TAB2 0010000 -#define TAB3 0014000 -#define BSDLY 0020000 -#define BS0 0000000 -#define BS1 0020000 -#define FFDLY 0100000 -#define FF0 0000000 -#define FF1 0100000 - -#define VTDLY 0040000 -#define VT0 0000000 -#define VT1 0040000 - -#define B0 0000000 -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 - -#define B57600 0010001 -#define B115200 0010002 -#define B230400 0010003 -#define B460800 0010004 -#define B500000 0010005 -#define B576000 0010006 -#define B921600 0010007 -#define B1000000 0010010 -#define B1152000 0010011 -#define B1500000 0010012 -#define B2000000 0010013 -#define B2500000 0010014 -#define B3000000 0010015 -#define B3500000 0010016 -#define B4000000 0010017 - -#define CSIZE 0000060 -#define CS5 0000000 -#define CS6 0000020 -#define CS7 0000040 -#define CS8 0000060 -#define CSTOPB 0000100 -#define CREAD 0000200 -#define PARENB 0000400 -#define PARODD 0001000 -#define HUPCL 0002000 -#define CLOCAL 0004000 - -#define ISIG 0000001 -#define ICANON 0000002 -#define ECHO 0000010 -#define ECHOE 0000020 -#define ECHOK 0000040 -#define ECHONL 0000100 -#define NOFLSH 0000200 -#define TOSTOP 0000400 -#define IEXTEN 0100000 - -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 - -#define TCSANOW 0 -#define TCSADRAIN 1 -#define TCSAFLUSH 2 - -#define EXTA 0000016 -#define EXTB 0000017 -#define CBAUD 0010017 -#define CBAUDEX 0010000 -#define CIBAUD 002003600000 -#define CMSPAR 010000000000 -#define CRTSCTS 020000000000 - -#define XCASE 0000004 -#define ECHOCTL 0001000 -#define ECHOPRT 0002000 -#define ECHOKE 0004000 -#define FLUSHO 0010000 -#define PENDIN 0040000 -#define EXTPROC 0200000 - -#define XTABS 0014000 - -speed_t cfgetospeed (const struct termios *); -speed_t cfgetispeed (const struct termios *); -int cfsetospeed (struct termios *, speed_t); -int cfsetispeed (struct termios *, speed_t); - -int tcgetattr (int, struct termios *); -int tcsetattr (int, int, const struct termios *); - -int tcsendbreak (int, int); -int tcdrain (int); -int tcflush (int, int); -int tcflow (int, int); - -pid_t tcgetsid (int); - -#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) -void cfmakeraw(struct termios *); -int cfsetspeed(struct termios *, speed_t); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -- cgit v1.3.1