import RT-Thread@9217865c without bsp, libcpu and components/net
This commit is contained in:
commit
e2376a3709
1414 changed files with 390370 additions and 0 deletions
10
components/libc/posix/io/README.md
Normal file
10
components/libc/posix/io/README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
This folder contains:
|
||||
|
||||
| sub-folders | description |
|
||||
| ----------- | ------------------------- |
|
||||
| aio | Asynchronous I/O |
|
||||
| mman | Memory-Mapped I/O |
|
||||
| poll | Nonblocking I/O |
|
||||
| stdio | Standard Input/Output I/O |
|
||||
| termios | Terminal I/O |
|
||||
|
15
components/libc/posix/io/SConscript
Normal file
15
components/libc/posix/io/SConscript
Normal file
|
@ -0,0 +1,15 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
group = []
|
||||
|
||||
list = os.listdir(cwd)
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
group = group + SConscript(os.path.join(d, 'SConscript'))
|
||||
|
||||
Return('group')
|
11
components/libc/posix/io/aio/SConscript
Normal file
11
components/libc/posix/io/aio/SConscript
Normal file
|
@ -0,0 +1,11 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = ['aio.c']
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('POSIX', src, depend = ['RT_USING_POSIX_AIO'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
463
components/libc/posix/io/aio/aio.c
Normal file
463
components/libc/posix/io/aio/aio.c
Normal file
|
@ -0,0 +1,463 @@
|
|||
/*
|
||||
* 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 <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/errno.h>
|
||||
#include "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_base_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_base_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_base_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_base_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)
|
||||
{
|
||||
rt_base_t level;
|
||||
int len, oflags;
|
||||
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_base_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
|
||||
* <aio.h> 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 <aio.h>. 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);
|
47
components/libc/posix/io/aio/aio.h
Normal file
47
components/libc/posix/io/aio/aio.h
Normal file
|
@ -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 __AIO_H__
|
||||
#define __AIO_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/signal.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
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
|
11
components/libc/posix/io/mman/SConscript
Normal file
11
components/libc/posix/io/mman/SConscript
Normal file
|
@ -0,0 +1,11 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = ['mman.c']
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('POSIX', src, depend = ['RT_USING_POSIX_MMAN'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
71
components/libc/posix/io/mman/mman.c
Normal file
71
components/libc/posix/io/mman/mman.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include "sys/mman.h"
|
||||
|
||||
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;
|
||||
}
|
60
components/libc/posix/io/mman/sys/mman.h
Normal file
60
components/libc/posix/io/mman/sys/mman.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __SYS_MMAN_H__
|
||||
#define __SYS_MMAN_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
|
||||
#define MAP_SHARED 0x01
|
||||
#define MAP_PRIVATE 0x02
|
||||
#define MAP_TYPE 0x0f
|
||||
#define MAP_FIXED 0x10
|
||||
#define MAP_ANON 0x20
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#define MAP_NORESERVE 0x4000
|
||||
#define MAP_GROWSDOWN 0x0100
|
||||
#define MAP_DENYWRITE 0x0800
|
||||
#define MAP_EXECUTABLE 0x1000
|
||||
#define MAP_LOCKED 0x2000
|
||||
#define MAP_POPULATE 0x8000
|
||||
#define MAP_NONBLOCK 0x10000
|
||||
#define MAP_STACK 0x20000
|
||||
#define MAP_HUGETLB 0x40000
|
||||
#define MAP_FILE 0
|
||||
|
||||
#define PROT_NONE 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
#define PROT_GROWSDOWN 0x01000000
|
||||
#define PROT_GROWSUP 0x02000000
|
||||
|
||||
#define MS_ASYNC 1
|
||||
#define MS_INVALIDATE 2
|
||||
#define MS_SYNC 4
|
||||
|
||||
#define MCL_CURRENT 1
|
||||
#define MCL_FUTURE 2
|
||||
#define MCL_ONFAULT 4
|
||||
|
||||
void *mmap (void *start, size_t len, int prot, int flags, int fd, off_t off);
|
||||
int munmap (void *start, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
17
components/libc/posix/io/poll/SConscript
Normal file
17
components/libc/posix/io/poll/SConscript
Normal file
|
@ -0,0 +1,17 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend('RT_USING_POSIX_POLL'):
|
||||
src += ['poll.c']
|
||||
|
||||
if GetDepend('RT_USING_POSIX_SELECT'):
|
||||
src += ['select.c']
|
||||
|
||||
group = DefineGroup('POSIX', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
228
components/libc/posix/io/poll/poll.c
Normal file
228
components/libc/posix/io/poll/poll.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016-12-28 Bernard first version
|
||||
* 2018-03-09 Bernard Add protection for pt->triggered.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <dfs_file.h>
|
||||
#include "poll.h"
|
||||
|
||||
struct rt_poll_node;
|
||||
|
||||
struct rt_poll_table
|
||||
{
|
||||
rt_pollreq_t req;
|
||||
rt_uint32_t triggered; /* the waited thread whether triggered */
|
||||
rt_thread_t polling_thread;
|
||||
struct rt_poll_node *nodes;
|
||||
};
|
||||
|
||||
struct rt_poll_node
|
||||
{
|
||||
struct rt_wqueue_node wqn;
|
||||
struct rt_poll_table *pt;
|
||||
struct rt_poll_node *next;
|
||||
};
|
||||
|
||||
static int __wqueue_pollwake(struct rt_wqueue_node *wait, void *key)
|
||||
{
|
||||
struct rt_poll_node *pn;
|
||||
|
||||
if (key && !((rt_ubase_t)key & wait->key))
|
||||
return -1;
|
||||
|
||||
pn = rt_container_of(wait, struct rt_poll_node, wqn);
|
||||
pn->pt->triggered = 1;
|
||||
|
||||
return __wqueue_default_wake(wait, key);
|
||||
}
|
||||
|
||||
static void _poll_add(rt_wqueue_t *wq, rt_pollreq_t *req)
|
||||
{
|
||||
struct rt_poll_table *pt;
|
||||
struct rt_poll_node *node;
|
||||
|
||||
node = (struct rt_poll_node *)rt_malloc(sizeof(struct rt_poll_node));
|
||||
if (node == RT_NULL)
|
||||
return;
|
||||
|
||||
pt = rt_container_of(req, struct rt_poll_table, req);
|
||||
|
||||
node->wqn.key = req->_key;
|
||||
rt_list_init(&(node->wqn.list));
|
||||
node->wqn.polling_thread = pt->polling_thread;
|
||||
node->wqn.wakeup = __wqueue_pollwake;
|
||||
node->next = pt->nodes;
|
||||
node->pt = pt;
|
||||
pt->nodes = node;
|
||||
rt_wqueue_add(wq, &node->wqn);
|
||||
}
|
||||
|
||||
static void poll_table_init(struct rt_poll_table *pt)
|
||||
{
|
||||
pt->req._proc = _poll_add;
|
||||
pt->triggered = 0;
|
||||
pt->nodes = RT_NULL;
|
||||
pt->polling_thread = rt_thread_self();
|
||||
}
|
||||
|
||||
static int poll_wait_timeout(struct rt_poll_table *pt, int msec)
|
||||
{
|
||||
rt_int32_t timeout;
|
||||
int ret = 0;
|
||||
struct rt_thread *thread;
|
||||
rt_base_t level;
|
||||
|
||||
thread = pt->polling_thread;
|
||||
|
||||
timeout = rt_tick_from_millisecond(msec);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (timeout != 0 && !pt->triggered)
|
||||
{
|
||||
if (rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE) == RT_EOK)
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_schedule();
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
}
|
||||
}
|
||||
|
||||
ret = !pt->triggered;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_pollfd(struct pollfd *pollfd, rt_pollreq_t *req)
|
||||
{
|
||||
int mask = 0;
|
||||
int fd;
|
||||
|
||||
fd = pollfd->fd;
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
struct dfs_file *f = fd_get(fd);
|
||||
mask = POLLNVAL;
|
||||
|
||||
if (f)
|
||||
{
|
||||
mask = POLLMASK_DEFAULT;
|
||||
if (f->vnode->fops->poll)
|
||||
{
|
||||
req->_key = pollfd->events | POLLERR | POLLHUP;
|
||||
|
||||
mask = f->vnode->fops->poll(f, req);
|
||||
|
||||
/* dealwith the device return error -1*/
|
||||
if (mask < 0)
|
||||
{
|
||||
pollfd->revents = 0;
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
/* Mask out unneeded events. */
|
||||
mask &= pollfd->events | POLLERR | POLLHUP;
|
||||
}
|
||||
}
|
||||
pollfd->revents = mask;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int poll_do(struct pollfd *fds, nfds_t nfds, struct rt_poll_table *pt, int msec)
|
||||
{
|
||||
int num;
|
||||
int istimeout = 0;
|
||||
nfds_t n;
|
||||
struct pollfd *pf;
|
||||
int ret = 0;
|
||||
|
||||
if (msec == 0)
|
||||
{
|
||||
pt->req._proc = RT_NULL;
|
||||
istimeout = 1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
pf = fds;
|
||||
num = 0;
|
||||
pt->triggered = 0;
|
||||
|
||||
for (n = 0; n < nfds; n ++)
|
||||
{
|
||||
ret = do_pollfd(pf, &pt->req);
|
||||
if(ret < 0)
|
||||
{
|
||||
/*dealwith the device return error -1 */
|
||||
pt->req._proc = RT_NULL;
|
||||
return ret;
|
||||
}
|
||||
else if(ret > 0)
|
||||
{
|
||||
num ++;
|
||||
pt->req._proc = RT_NULL;
|
||||
}
|
||||
pf ++;
|
||||
}
|
||||
|
||||
pt->req._proc = RT_NULL;
|
||||
|
||||
if (num || istimeout)
|
||||
break;
|
||||
|
||||
if (poll_wait_timeout(pt, msec))
|
||||
istimeout = 1;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static void poll_teardown(struct rt_poll_table *pt)
|
||||
{
|
||||
struct rt_poll_node *node, *next;
|
||||
|
||||
next = pt->nodes;
|
||||
while (next)
|
||||
{
|
||||
node = next;
|
||||
rt_wqueue_remove(&node->wqn);
|
||||
next = node->next;
|
||||
rt_free(node);
|
||||
}
|
||||
}
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
||||
{
|
||||
int num;
|
||||
struct rt_poll_table table;
|
||||
|
||||
poll_table_init(&table);
|
||||
|
||||
num = poll_do(fds, nfds, &table, timeout);
|
||||
|
||||
poll_teardown(&table);
|
||||
|
||||
return num;
|
||||
}
|
50
components/libc/posix/io/poll/poll.h
Normal file
50
components/libc/posix/io/poll/poll.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-11 Meco Man First version
|
||||
*/
|
||||
|
||||
#ifndef __POLL_H__
|
||||
#define __POLL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !defined(POLLIN) && !defined(POLLOUT)
|
||||
#define POLLIN (0x01)
|
||||
#define POLLRDNORM (0x01)
|
||||
#define POLLRDBAND (0x01)
|
||||
#define POLLPRI (0x01)
|
||||
|
||||
#define POLLOUT (0x02)
|
||||
#define POLLWRNORM (0x02)
|
||||
#define POLLWRBAND (0x02)
|
||||
|
||||
#define POLLERR (0x04)
|
||||
#define POLLHUP (0x08)
|
||||
#define POLLNVAL (0x10)
|
||||
|
||||
typedef unsigned int nfds_t;
|
||||
|
||||
struct pollfd
|
||||
{
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
#endif /* !defined(POLLIN) && !defined(POLLOUT) */
|
||||
|
||||
#define POLLMASK_DEFAULT (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __POLL_H__ */
|
177
components/libc/posix/io/poll/select.c
Normal file
177
components/libc/posix/io/poll/select.c
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016-12-28 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <poll.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
static void fdszero(fd_set *set, int nfds)
|
||||
{
|
||||
fd_mask *m;
|
||||
int n;
|
||||
|
||||
/*
|
||||
The 'sizeof(fd_set)' of the system space may differ from user space,
|
||||
so the actual size of the 'fd_set' is determined here with the parameter 'nfds'
|
||||
*/
|
||||
m = (fd_mask *)set;
|
||||
for (n = 0; n < nfds; n += (sizeof(fd_mask) * 8))
|
||||
{
|
||||
rt_memset(m, 0, sizeof(fd_mask));
|
||||
m ++;
|
||||
}
|
||||
}
|
||||
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
|
||||
{
|
||||
int fd;
|
||||
int npfds;
|
||||
int msec;
|
||||
int ndx;
|
||||
int ret;
|
||||
struct pollfd *pollset = RT_NULL;
|
||||
|
||||
/* How many pollfd structures do we need to allocate? */
|
||||
for (fd = 0, npfds = 0; fd < nfds; fd++)
|
||||
{
|
||||
/* Check if any monitor operation is requested on this fd */
|
||||
if ((readfds && FD_ISSET(fd, readfds)) ||
|
||||
(writefds && FD_ISSET(fd, writefds)) ||
|
||||
(exceptfds && FD_ISSET(fd, exceptfds)))
|
||||
{
|
||||
npfds++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate the descriptor list for poll() */
|
||||
if (npfds > 0)
|
||||
{
|
||||
pollset = (struct pollfd *)rt_calloc(npfds, sizeof(struct pollfd));
|
||||
if (!pollset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the descriptor list for poll() */
|
||||
for (fd = 0, ndx = 0; fd < nfds; fd++)
|
||||
{
|
||||
int incr = 0;
|
||||
|
||||
/* The readfs set holds the set of FDs that the caller can be assured
|
||||
* of reading from without blocking. Note that POLLHUP is included as
|
||||
* a read-able condition. POLLHUP will be reported at the end-of-file
|
||||
* or when a connection is lost. In either case, the read() can then
|
||||
* be performed without blocking.
|
||||
*/
|
||||
|
||||
if (readfds && FD_ISSET(fd, readfds))
|
||||
{
|
||||
pollset[ndx].fd = fd;
|
||||
pollset[ndx].events |= POLLIN;
|
||||
incr = 1;
|
||||
}
|
||||
|
||||
if (writefds && FD_ISSET(fd, writefds))
|
||||
{
|
||||
pollset[ndx].fd = fd;
|
||||
pollset[ndx].events |= POLLOUT;
|
||||
incr = 1;
|
||||
}
|
||||
|
||||
if (exceptfds && FD_ISSET(fd, exceptfds))
|
||||
{
|
||||
pollset[ndx].fd = fd;
|
||||
incr = 1;
|
||||
}
|
||||
|
||||
ndx += incr;
|
||||
}
|
||||
|
||||
RT_ASSERT(ndx == npfds);
|
||||
|
||||
/* Convert the timeout to milliseconds */
|
||||
if (timeout)
|
||||
{
|
||||
msec = (int)timeout->tv_sec * 1000 + (int)timeout->tv_usec / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
msec = -1;
|
||||
}
|
||||
|
||||
/* Then let poll do all of the real work. */
|
||||
|
||||
ret = poll(pollset, npfds, msec);
|
||||
|
||||
/* Now set up the return values */
|
||||
if (readfds)
|
||||
{
|
||||
fdszero(readfds, nfds);
|
||||
}
|
||||
|
||||
if (writefds)
|
||||
{
|
||||
fdszero(writefds, nfds);
|
||||
}
|
||||
|
||||
if (exceptfds)
|
||||
{
|
||||
fdszero(exceptfds, nfds);
|
||||
}
|
||||
|
||||
/* Convert the poll descriptor list back into selects 3 bitsets */
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
ret = 0;
|
||||
for (ndx = 0; ndx < npfds; ndx++)
|
||||
{
|
||||
/* Check for read conditions. Note that POLLHUP is included as a
|
||||
* read condition. POLLHUP will be reported when no more data will
|
||||
* be available (such as when a connection is lost). In either
|
||||
* case, the read() can then be performed without blocking.
|
||||
*/
|
||||
|
||||
if (readfds)
|
||||
{
|
||||
if (pollset[ndx].revents & (POLLIN | POLLHUP))
|
||||
{
|
||||
FD_SET(pollset[ndx].fd, readfds);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for write conditions */
|
||||
if (writefds)
|
||||
{
|
||||
if (pollset[ndx].revents & POLLOUT)
|
||||
{
|
||||
FD_SET(pollset[ndx].fd, writefds);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for exceptions */
|
||||
if (exceptfds)
|
||||
{
|
||||
if (pollset[ndx].revents & POLLERR)
|
||||
{
|
||||
FD_SET(pollset[ndx].fd, exceptfds);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pollset) rt_free(pollset);
|
||||
|
||||
return ret;
|
||||
}
|
22
components/libc/posix/io/stdio/SConscript
Normal file
22
components/libc/posix/io/stdio/SConscript
Normal file
|
@ -0,0 +1,22 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
src = []
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd]
|
||||
group = []
|
||||
|
||||
if GetDepend('RT_USING_POSIX_STDIO'):
|
||||
src += ['libc.c']
|
||||
|
||||
group = DefineGroup('POSIX', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
list = os.listdir(cwd)
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
group = group + SConscript(os.path.join(d, 'SConscript'))
|
||||
|
||||
Return('group')
|
221
components/libc/posix/io/stdio/libc.c
Normal file
221
components/libc/posix/io/stdio/libc.c
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017/10/15 bernard the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/errno.h>
|
||||
#include "libc.h"
|
||||
|
||||
#define STDIO_DEVICE_NAME_MAX 32
|
||||
|
||||
int sys_dup2(int oldfd, int new);
|
||||
|
||||
int libc_system_init(void)
|
||||
{
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
rt_device_t dev_console;
|
||||
|
||||
dev_console = rt_console_get_device();
|
||||
if (dev_console)
|
||||
{
|
||||
int fd = libc_stdio_set_console(dev_console->parent.name, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
/* set fd (0, 1, 2) */
|
||||
sys_dup2(fd, 0);
|
||||
sys_dup2(fd, 1);
|
||||
sys_dup2(fd, 2);
|
||||
}
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(libc_system_init);
|
||||
|
||||
#if defined(RT_USING_POSIX_STDIO) && defined(RT_USING_NEWLIBC)
|
||||
|
||||
static FILE* std_console = NULL;
|
||||
int libc_stdio_set_console(const char* device_name, int mode)
|
||||
{
|
||||
FILE *fp;
|
||||
char name[STDIO_DEVICE_NAME_MAX];
|
||||
char *file_mode;
|
||||
|
||||
rt_snprintf(name, sizeof(name) - 1, "/dev/%s", device_name);
|
||||
name[STDIO_DEVICE_NAME_MAX - 1] = '\0';
|
||||
|
||||
if (mode == O_RDWR)
|
||||
{
|
||||
file_mode = "r+";
|
||||
}
|
||||
else if (mode == O_WRONLY)
|
||||
{
|
||||
file_mode = "wb";
|
||||
}
|
||||
else
|
||||
{
|
||||
file_mode = "rb";
|
||||
}
|
||||
|
||||
fp = fopen(name, file_mode);
|
||||
if (fp)
|
||||
{
|
||||
setvbuf(fp, NULL, _IONBF, 0);
|
||||
|
||||
if (std_console)
|
||||
{
|
||||
fclose(std_console);
|
||||
std_console = NULL;
|
||||
}
|
||||
std_console = fp;
|
||||
|
||||
if (mode == O_RDWR)
|
||||
{
|
||||
_GLOBAL_REENT->_stdin = std_console;
|
||||
}
|
||||
else
|
||||
{
|
||||
_GLOBAL_REENT->_stdin = NULL;
|
||||
}
|
||||
|
||||
if (mode == O_RDONLY)
|
||||
{
|
||||
_GLOBAL_REENT->_stdout = NULL;
|
||||
_GLOBAL_REENT->_stderr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_GLOBAL_REENT->_stdout = std_console;
|
||||
_GLOBAL_REENT->_stderr = std_console;
|
||||
}
|
||||
|
||||
_GLOBAL_REENT->__sdidinit = 1;
|
||||
}
|
||||
|
||||
if (std_console)
|
||||
return fileno(std_console);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int libc_stdio_get_console(void)
|
||||
{
|
||||
if (std_console)
|
||||
return fileno(std_console);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#elif defined(RT_USING_POSIX_STDIO) && defined(RT_USING_MUSLLIBC)
|
||||
|
||||
static FILE* std_console = NULL;
|
||||
|
||||
int libc_stdio_set_console(const char* device_name, int mode)
|
||||
{
|
||||
FILE *fp;
|
||||
char name[STDIO_DEVICE_NAME_MAX];
|
||||
char *file_mode;
|
||||
|
||||
rt_snprintf(name, sizeof(name) - 1, "/dev/%s", device_name);
|
||||
name[STDIO_DEVICE_NAME_MAX - 1] = '\0';
|
||||
|
||||
if (mode == O_RDWR) file_mode = "r+";
|
||||
else if (mode == O_WRONLY) file_mode = "wb";
|
||||
else file_mode = "rb";
|
||||
|
||||
fp = fopen(name, file_mode);
|
||||
if (fp)
|
||||
{
|
||||
setvbuf(fp, NULL, _IONBF, 0);
|
||||
|
||||
if (std_console)
|
||||
{
|
||||
fclose(std_console);
|
||||
std_console = NULL;
|
||||
}
|
||||
std_console = fp;
|
||||
}
|
||||
|
||||
if (std_console)
|
||||
{
|
||||
int fd = fileno(std_console);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int libc_stdio_get_console(void)
|
||||
{
|
||||
int ret = -1;
|
||||
if (std_console)
|
||||
{
|
||||
ret = fileno(std_console);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#elif defined(RT_USING_POSIX_STDIO)
|
||||
|
||||
static int std_fd = -1;
|
||||
int libc_stdio_set_console(const char* device_name, int mode)
|
||||
{
|
||||
int fd;
|
||||
char name[STDIO_DEVICE_NAME_MAX];
|
||||
|
||||
rt_snprintf(name, sizeof(name) - 1, "/dev/%s", device_name);
|
||||
name[STDIO_DEVICE_NAME_MAX - 1] = '\0';
|
||||
|
||||
fd = open(name, mode, 0);
|
||||
if (fd >= 0)
|
||||
{
|
||||
if (std_fd >= 0)
|
||||
{
|
||||
close(std_fd);
|
||||
}
|
||||
std_fd = fd;
|
||||
}
|
||||
|
||||
return std_fd;
|
||||
}
|
||||
|
||||
int libc_stdio_get_console(void) {
|
||||
return std_fd;
|
||||
}
|
||||
#endif /* defined(RT_USING_POSIX_STDIO) && defined(RT_USING_NEWLIBC) */
|
||||
|
||||
int isatty(int fd)
|
||||
{
|
||||
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
|
||||
if(fd == STDOUT_FILENO || fd == STDERR_FILENO)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
if(fd == STDIN_FILENO)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
rt_set_errno(ENOTTY);
|
||||
return 0;
|
||||
}
|
||||
RTM_EXPORT(isatty);
|
30
components/libc/posix/io/stdio/libc.h
Normal file
30
components/libc/posix/io/stdio/libc.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017/10/15 bernard the first version
|
||||
*/
|
||||
|
||||
#ifndef __RTT_LIBC_H__
|
||||
#define __RTT_LIBC_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int libc_system_init(void);
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
int libc_stdio_get_console(void);
|
||||
int libc_stdio_set_console(const char* device_name, int mode);
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
11
components/libc/posix/io/termios/SConscript
Normal file
11
components/libc/posix/io/termios/SConscript
Normal file
|
@ -0,0 +1,11 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = ['termios.c']
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('POSIX', src, depend = ['RT_USING_POSIX_TERMIOS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
129
components/libc/posix/io/termios/termios.c
Normal file
129
components/libc/posix/io/termios/termios.c
Normal file
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/errno.h>
|
||||
#include "termios.h"
|
||||
#include <rtthread.h>
|
||||
|
||||
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*)(rt_ubase_t)queue);
|
||||
}
|
||||
|
||||
int tcflow(int fd, int action)
|
||||
{
|
||||
return ioctl(fd, TCXONC, (void*)(rt_ubase_t)action);
|
||||
}
|
||||
|
||||
/**
|
||||
* this function waits for transmission of output
|
||||
*/
|
||||
int tcdrain(int fd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
234
components/libc/posix/io/termios/termios.h
Normal file
234
components/libc/posix/io/termios/termios.h
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* 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
|
||||
* 2021/12/10 linzhenxing put tty system
|
||||
*/
|
||||
|
||||
#ifndef __TERMIOS_H__
|
||||
#define __TERMIOS_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
/* c_cc characters */
|
||||
#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
|
||||
|
||||
/* c_iflag bits */
|
||||
#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
|
||||
|
||||
/* c_oflag bits */
|
||||
#define OPOST 0000001
|
||||
#define ONLCR 0000002
|
||||
#define OLCUC 0000004
|
||||
|
||||
#define OCRNL 0000010
|
||||
#define ONOCR 0000020
|
||||
#define ONLRET 0000040
|
||||
|
||||
#define OFILL 00000100
|
||||
#define OFDEL 00000200
|
||||
#define NLDLY 00001400
|
||||
#define NL0 00000000
|
||||
#define NL1 00000400
|
||||
#define NL2 00001000
|
||||
#define NL3 00001400
|
||||
#define TABDLY 00006000
|
||||
#define TAB0 00000000
|
||||
#define TAB1 00002000
|
||||
#define TAB2 00004000
|
||||
#define TAB3 00006000
|
||||
#define CRDLY 00030000
|
||||
#define KCR0 00000000
|
||||
#define KCR1 00010000
|
||||
#define KCR2 00020000
|
||||
#define KCR3 00030000
|
||||
#define FFDLY 00040000
|
||||
#define FF0 00000000
|
||||
#define FF1 00040000
|
||||
#define BSDLY 00100000
|
||||
#define BS0 00000000
|
||||
#define BS1 00100000
|
||||
#define VTDLY 00200000
|
||||
#define VT0 00000000
|
||||
#define VT1 00200000
|
||||
#define XTABS 01000000
|
||||
|
||||
#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
|
||||
|
||||
/* c_lflag bits */
|
||||
#define ISIG 0000001
|
||||
#define ICANON 0000002
|
||||
#define XCASE 0000004
|
||||
#define ECHO 0000010
|
||||
#define ECHOE 0000020
|
||||
#define ECHOK 0000040
|
||||
#define ECHONL 0000100
|
||||
#define NOFLSH 0000200
|
||||
#define TOSTOP 0000400
|
||||
#define ECHOCTL 0001000
|
||||
#define ECHOPRT 0002000
|
||||
#define ECHOKE 0004000
|
||||
#define FLUSHO 0010000
|
||||
#define PENDIN 0040000
|
||||
#define IEXTEN 0100000
|
||||
#define EXTPROC 0200000
|
||||
|
||||
#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
|
||||
|
||||
/* intr=^C quit=^| erase=del kill=^U
|
||||
eof=^D vtime=\0 vmin=\1 sxtc=\0
|
||||
start=^Q stop=^S susp=^Z eol=\0
|
||||
reprint=^R discard=^U werase=^W lnext=^V
|
||||
eol2=\0
|
||||
*/
|
||||
#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
|
||||
|
||||
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);
|
||||
|
||||
void cfmakeraw(struct termios *);
|
||||
int cfsetspeed(struct termios *, speed_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue