sdio+fatfs创建
This commit is contained in:
commit
f762d5d7f8
2473 files changed
+1192014
No files matched your search
@@ -0,0 +1,11 @@
|
||||
menu "C/C++ and POSIX layer"
|
||||
|
||||
config RT_LIBC_DEFAULT_TIMEZONE
|
||||
int "Set the default time zone (UTC+)"
|
||||
range -12 12
|
||||
default 8
|
||||
|
||||
source "$RTT_DIR/components/libc/posix/Kconfig"
|
||||
source "$RTT_DIR/components/libc/cplusplus/Kconfig"
|
||||
|
||||
endmenu
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -0,0 +1,5 @@
|
||||
# ARMLIB (Keil-MDK) porting for RT-Thread
|
||||
|
||||
https://www.keil.com/support/man/docs/armlib/
|
||||
|
||||
https://www.keil.com/support/man/docs/armlib/armlib_chr1358938918041.htm
|
||||
@@ -0,0 +1,12 @@
|
||||
from building import *
|
||||
Import('rtconfig')
|
||||
|
||||
src = Glob('*.c')
|
||||
group = []
|
||||
|
||||
CPPDEFINES = ['RT_USING_ARM_LIBC']
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
group = DefineGroup('Compiler', src, depend = [''], CPPDEFINES = CPPDEFINES)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-08-03 bernard Add file header
|
||||
* 2021-11-13 Meco Man implement no-heap warning
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef RT_USING_HEAP
|
||||
#define DBG_TAG "armlibc.syscall.mem"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define _NO_HEAP_ERROR() do{LOG_E("Please enable RT_USING_HEAP");\
|
||||
RT_ASSERT(0);\
|
||||
}while(0)
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
#ifdef __CC_ARM
|
||||
/* avoid the heap and heap-using library functions supplied by arm */
|
||||
#pragma import(__use_no_heap)
|
||||
#endif /* __CC_ARM */
|
||||
|
||||
void *malloc(size_t n)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
return rt_malloc(n);
|
||||
#else
|
||||
_NO_HEAP_ERROR();
|
||||
return RT_NULL;
|
||||
#endif
|
||||
}
|
||||
RTM_EXPORT(malloc);
|
||||
|
||||
void *realloc(void *rmem, size_t newsize)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
return rt_realloc(rmem, newsize);
|
||||
#else
|
||||
_NO_HEAP_ERROR();
|
||||
return RT_NULL;
|
||||
#endif
|
||||
}
|
||||
RTM_EXPORT(realloc);
|
||||
|
||||
void *calloc(size_t nelem, size_t elsize)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
return rt_calloc(nelem, elsize);
|
||||
#else
|
||||
_NO_HEAP_ERROR();
|
||||
return RT_NULL;
|
||||
#endif
|
||||
}
|
||||
RTM_EXPORT(calloc);
|
||||
|
||||
void free(void *rmem)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_free(rmem);
|
||||
#else
|
||||
_NO_HEAP_ERROR();
|
||||
#endif
|
||||
}
|
||||
RTM_EXPORT(free);
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-11-23 Yihui The first version
|
||||
* 2013-11-24 aozima fixed _sys_read()/_sys_write() issues.
|
||||
* 2014-08-03 bernard If using msh, use system() implementation
|
||||
* in msh.
|
||||
* 2020-08-05 Meco Man fixed _sys_flen() compiling-warning when
|
||||
* RT_USING_DFS is not defined
|
||||
* 2020-02-13 Meco Man re-implement exit() and abort()
|
||||
* 2020-02-14 Meco Man implement _sys_tmpnam()
|
||||
*/
|
||||
|
||||
#include <rt_sys.h>
|
||||
#include <rtthread.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <compiler_private.h>
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
#include "libc.h"
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
|
||||
#define DBG_TAG "armlibc.syscalls"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef __clang__
|
||||
__asm(".global __use_no_semihosting\n\t");
|
||||
#else
|
||||
#pragma import(__use_no_semihosting_swi)
|
||||
#endif
|
||||
|
||||
/* Standard IO device handles. */
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
#define STDERR 2
|
||||
|
||||
/* Standard IO device name defines. */
|
||||
const char __stdin_name[] = "STDIN";
|
||||
const char __stdout_name[] = "STDOUT";
|
||||
const char __stderr_name[] = "STDERR";
|
||||
|
||||
/**
|
||||
* required by fopen() and freopen().
|
||||
*
|
||||
* @param name - file name with path.
|
||||
* @param openmode - a bitmap hose bits mostly correspond directly to
|
||||
* the ISO mode specification.
|
||||
* @return -1 if an error occurs.
|
||||
*/
|
||||
FILEHANDLE _sys_open(const char *name, int openmode)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int fd;
|
||||
int mode = O_RDONLY;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
|
||||
/* Register standard Input Output devices. */
|
||||
if (strcmp(name, __stdin_name) == 0)
|
||||
return (STDIN);
|
||||
if (strcmp(name, __stdout_name) == 0)
|
||||
return (STDOUT);
|
||||
if (strcmp(name, __stderr_name) == 0)
|
||||
return (STDERR);
|
||||
|
||||
#ifndef DFS_USING_POSIX
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
return 0; /* error */
|
||||
#else
|
||||
/* Correct openmode from fopen to open */
|
||||
if (openmode & OPEN_PLUS)
|
||||
{
|
||||
if (openmode & OPEN_W)
|
||||
{
|
||||
mode |= (O_RDWR | O_TRUNC | O_CREAT);
|
||||
}
|
||||
else if (openmode & OPEN_A)
|
||||
{
|
||||
mode |= (O_RDWR | O_APPEND | O_CREAT);
|
||||
}
|
||||
else
|
||||
mode |= O_RDWR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (openmode & OPEN_W)
|
||||
{
|
||||
mode |= (O_WRONLY | O_TRUNC | O_CREAT);
|
||||
}
|
||||
else if (openmode & OPEN_A)
|
||||
{
|
||||
mode |= (O_WRONLY | O_APPEND | O_CREAT);
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(name, mode, 0);
|
||||
if (fd < 0)
|
||||
return 0; /* error */
|
||||
else
|
||||
return fd;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
int _sys_close(FILEHANDLE fh)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
if (fh <= STDERR)
|
||||
return 0; /* error */
|
||||
|
||||
return close(fh);
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
return 0;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from a file. Can return:
|
||||
* - zero if the read was completely successful
|
||||
* - the number of bytes _not_ read, if the read was partially successful
|
||||
* - the number of bytes not read, plus the top bit set (0x80000000), if
|
||||
* the read was partially successful due to end of file
|
||||
* - -1 if some error other than EOF occurred
|
||||
*
|
||||
* It is also legal to signal EOF by returning no data but
|
||||
* signalling no error (i.e. the top-bit-set mechanism need never
|
||||
* be used).
|
||||
*
|
||||
* So if (for example) the user is trying to read 8 bytes at a time
|
||||
* from a file in which only 5 remain, this routine can do three
|
||||
* equally valid things:
|
||||
*
|
||||
* - it can return 0x80000003 (3 bytes not read due to EOF)
|
||||
* - OR it can return 3 (3 bytes not read), and then return
|
||||
* 0x80000008 (8 bytes not read due to EOF) on the next attempt
|
||||
* - OR it can return 3 (3 bytes not read), and then return
|
||||
* 8 (8 bytes not read, meaning 0 read, meaning EOF) on the next
|
||||
* attempt
|
||||
*
|
||||
* `mode' exists for historical reasons and must be ignored.
|
||||
*/
|
||||
int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int size;
|
||||
|
||||
if (fh == STDIN)
|
||||
{
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
if (libc_stdio_get_console() < 0)
|
||||
{
|
||||
LOG_W("Do not invoke standard output before initializing Compiler");
|
||||
return 0; /* error, but keep going */
|
||||
}
|
||||
size = read(STDIN_FILENO, buf, len);
|
||||
return len - size; /* success */
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_STDIO);
|
||||
return 0; /* error */
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
}
|
||||
else if (fh == STDOUT || fh == STDERR)
|
||||
{
|
||||
return -1; /* 100% error */
|
||||
}
|
||||
else
|
||||
{
|
||||
size = read(fh, buf, len);
|
||||
if (size >= 0)
|
||||
{
|
||||
return len - size; /* success */
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; /* error */
|
||||
}
|
||||
}
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
return 0; /* error */
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to a file. Returns 0 on success, negative on error, and
|
||||
* the number of characters _not_ written on partial success.
|
||||
* `mode' exists for historical reasons and must be ignored.
|
||||
* The return value is either:
|
||||
* A positive number representing the number of characters not written
|
||||
* (so any nonzero return value denotes a failure of some sort).
|
||||
* A negative number indicating an error.
|
||||
*/
|
||||
int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int size;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
|
||||
if (fh == STDOUT || fh == STDERR)
|
||||
{
|
||||
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
|
||||
rt_device_t console;
|
||||
console = rt_console_get_device();
|
||||
if (console)
|
||||
{
|
||||
rt_device_write(console, -1, buf, len);
|
||||
}
|
||||
return 0; /* success */
|
||||
#else
|
||||
return 0; /* error */
|
||||
#endif /* defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE) */
|
||||
}
|
||||
else if (fh == STDIN)
|
||||
{
|
||||
return -1; /* 100% error */
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
size = write(fh, buf, len);
|
||||
if (size >= 0)
|
||||
{
|
||||
return len - size; /* success */
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; /* error */
|
||||
}
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
return 0; /* error */
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the file position to a given offset from the file start.
|
||||
* Returns >=0 on success, <0 on failure.
|
||||
*/
|
||||
int _sys_seek(FILEHANDLE fh, long pos)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
if (fh < STDERR)
|
||||
return 0; /* error */
|
||||
|
||||
/* position is relative to the start of file fh */
|
||||
return lseek(fh, pos, 0);
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
return 0; /* error */
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
/**
|
||||
* used by tmpnam() or tmpfile()
|
||||
*/
|
||||
int _sys_tmpnam(char *name, int fileno, unsigned maxlength)
|
||||
{
|
||||
rt_snprintf(name, maxlength, "tem%03d", fileno);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *_sys_command_string(char *cmd, int len)
|
||||
{
|
||||
/* no support */
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* This function writes a character to the console. */
|
||||
void _ttywrch(int ch)
|
||||
{
|
||||
#ifdef RT_USING_CONSOLE
|
||||
rt_kprintf("%c", (char)ch);
|
||||
#endif /* RT_USING_CONSOLE */
|
||||
}
|
||||
|
||||
/* for exit() and abort() */
|
||||
RT_WEAK void _sys_exit(int return_code)
|
||||
{
|
||||
extern void __rt_libc_exit(int status);
|
||||
__rt_libc_exit(return_code);
|
||||
while(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* return current length of file.
|
||||
*
|
||||
* @param fh - file handle
|
||||
* @return file length, or -1 on failed
|
||||
*/
|
||||
long _sys_flen(FILEHANDLE fh)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
struct stat stat;
|
||||
|
||||
if (fh < STDERR)
|
||||
return 0; /* error */
|
||||
|
||||
fstat(fh, &stat);
|
||||
return stat.st_size;
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
return 0;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
int _sys_istty(FILEHANDLE fh)
|
||||
{
|
||||
if((STDIN <= fh) && (fh <= STDERR))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remove(const char *filename)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
return unlink(filename);
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
return 0; /* error */
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
#ifdef __MICROLIB
|
||||
#include <stdio.h>
|
||||
|
||||
int fputc(int c, FILE *f)
|
||||
{
|
||||
#ifdef RT_USING_CONSOLE
|
||||
rt_kprintf("%c", (char)c);
|
||||
return 1;
|
||||
#else
|
||||
return 0; /* error */
|
||||
#endif /* RT_USING_CONSOLE */
|
||||
}
|
||||
|
||||
int fgetc(FILE *f)
|
||||
{
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
char ch;
|
||||
|
||||
if (libc_stdio_get_console() < 0)
|
||||
{
|
||||
LOG_W("Do not invoke standard output before initializing Compiler");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(read(STDIN_FILENO, &ch, 1) == 1)
|
||||
return ch;
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_STDIO);
|
||||
return 0; /* error */
|
||||
}
|
||||
|
||||
#endif /* __MICROLIB */
|
||||
@@ -0,0 +1,22 @@
|
||||
from building import *
|
||||
Import('rtconfig')
|
||||
|
||||
src = []
|
||||
cwd = GetCurrentDir()
|
||||
group = []
|
||||
CPPPATH = [cwd]
|
||||
CPPDEFINES = []
|
||||
|
||||
if rtconfig.CROSS_TOOL == 'keil':
|
||||
CPPDEFINES += ['__CLK_TCK=RT_TICK_PER_SECOND']
|
||||
|
||||
src += Glob('*.c')
|
||||
|
||||
group = DefineGroup('Compiler', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)
|
||||
|
||||
list = os.listdir(cwd)
|
||||
for item in list:
|
||||
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
|
||||
group = group + SConscript(os.path.join(item, 'SConscript'))
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-12-26 Meco Man First Version
|
||||
*/
|
||||
|
||||
#ifndef __COMPILER_PRIVATE_H__
|
||||
#define __COMPILER_PRIVATE_H__
|
||||
|
||||
#define _WARNING_WITHOUT_FS "Please enable RT_USING_POSIX_FS"
|
||||
#define _WARNING_WITHOUT_STDIO "Please enable RT_USING_POSIX_FS and RT_USING_POSIX_STDIO"
|
||||
|
||||
#endif /* __COMPILER_PRIVATE_H__ */
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __DIRENT_H__
|
||||
#define __DIRENT_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* dirent.h - format of directory entries
|
||||
* Ref: http://www.opengroup.org/onlinepubs/009695399/basedefs/dirent.h.html
|
||||
*/
|
||||
|
||||
/* File types */
|
||||
#define FT_REGULAR 0 /* regular file */
|
||||
#define FT_SOCKET 1 /* socket file */
|
||||
#define FT_DIRECTORY 2 /* directory */
|
||||
#define FT_USER 3 /* user defined */
|
||||
|
||||
#define DT_UNKNOWN 0x00
|
||||
#define DT_REG 0x01
|
||||
#define DT_DIR 0x02
|
||||
|
||||
#ifndef HAVE_DIR_STRUCTURE
|
||||
#define HAVE_DIR_STRUCTURE
|
||||
typedef struct
|
||||
{
|
||||
int fd; /* directory file */
|
||||
char buf[512];
|
||||
int num;
|
||||
int cur;
|
||||
}DIR;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DIRENT_STRUCTURE
|
||||
#define HAVE_DIRENT_STRUCTURE
|
||||
|
||||
#define DIRENT_NAME_MAX 256
|
||||
|
||||
struct dirent
|
||||
{
|
||||
rt_uint8_t d_type; /* The type of the file */
|
||||
rt_uint8_t d_namlen; /* The length of the not including the terminating null file name */
|
||||
rt_uint16_t d_reclen; /* length of this record */
|
||||
char d_name[DIRENT_NAME_MAX]; /* The null-terminated file name */
|
||||
};
|
||||
#endif
|
||||
|
||||
int closedir(DIR *);
|
||||
DIR *opendir(const char *);
|
||||
struct dirent *readdir(DIR *);
|
||||
int readdir_r(DIR *, struct dirent *, struct dirent **);
|
||||
void rewinddir(DIR *);
|
||||
void seekdir(DIR *, long int);
|
||||
long telldir(DIR *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
src = []
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd]
|
||||
group = []
|
||||
|
||||
src += Glob('*.c')
|
||||
|
||||
if rtconfig.PLATFORM != 'gcc' or rtconfig.ARCH == 'sim':
|
||||
group = DefineGroup('Compiler', src, depend = [''], CPPPATH = CPPPATH)
|
||||
Return('group')
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-02 Meco Man First version
|
||||
*/
|
||||
|
||||
#ifndef __FCNTL_H__
|
||||
#define __FCNTL_H__
|
||||
|
||||
#include "sys/types.h"
|
||||
|
||||
#define O_RDONLY 00
|
||||
#define O_WRONLY 01
|
||||
#define O_RDWR 02
|
||||
|
||||
#define O_CREAT 0100
|
||||
#define O_EXCL 0200
|
||||
#define O_NOCTTY 0400
|
||||
#define O_TRUNC 01000
|
||||
#define O_APPEND 02000
|
||||
#define O_NONBLOCK 04000
|
||||
#define O_DSYNC 010000
|
||||
#define O_SYNC 04010000
|
||||
#define O_RSYNC 04010000
|
||||
#define O_BINARY 0100000
|
||||
#define O_DIRECTORY 0200000
|
||||
#define O_NOFOLLOW 0400000
|
||||
#define O_CLOEXEC 02000000
|
||||
|
||||
#define O_ASYNC 020000
|
||||
#define O_DIRECT 040000
|
||||
#define O_LARGEFILE 0100000
|
||||
#define O_NOATIME 01000000
|
||||
#define O_PATH 010000000
|
||||
#define O_TMPFILE 020200000
|
||||
#define O_NDELAY O_NONBLOCK
|
||||
|
||||
#define O_SEARCH O_PATH
|
||||
#define O_EXEC O_PATH
|
||||
|
||||
#define O_ACCMODE (03|O_SEARCH)
|
||||
|
||||
#define F_DUPFD 0
|
||||
#define F_GETFD 1
|
||||
#define F_SETFD 2
|
||||
#define F_GETFL 3
|
||||
#define F_SETFL 4
|
||||
|
||||
#define F_SETOWN 8
|
||||
#define F_GETOWN 9
|
||||
#define F_SETSIG 10
|
||||
#define F_GETSIG 11
|
||||
|
||||
#define F_GETLK 12
|
||||
#define F_SETLK 13
|
||||
#define F_SETLKW 14
|
||||
|
||||
#define F_SETOWN_EX 15
|
||||
#define F_GETOWN_EX 16
|
||||
|
||||
#define F_GETOWNER_UIDS 17
|
||||
|
||||
int open(const char *file, int flags, ...);
|
||||
int fcntl(int fildes, int cmd, ...);
|
||||
int creat(const char *path, mode_t mode);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
## Attentions
|
||||
|
||||
This folder is "common" for toolchains, which only support ISO C, as an extension part, such as Keil-MDK and IAR.
|
||||
|
||||
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-05-22 Meco Man The first version.
|
||||
*/
|
||||
|
||||
#ifndef __SYS_ERRNO_H__
|
||||
#define __SYS_ERRNO_H__
|
||||
|
||||
#if defined(__ARMCC_VERSION)
|
||||
/*
|
||||
defined in armcc/errno.h
|
||||
|
||||
#define EDOM 1
|
||||
#define ERANGE 2
|
||||
#define EILSEQ 4
|
||||
#define ESIGNUM 3
|
||||
#define EINVAL 5
|
||||
#define ENOMEM 6
|
||||
*/
|
||||
|
||||
#define ERROR_BASE_NO 7
|
||||
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
/* defined in iar/errno.h
|
||||
#define EDOM 33
|
||||
#define ERANGE 34
|
||||
#define EFPOS 35
|
||||
#define EILSEQ 36
|
||||
*/
|
||||
#define ERROR_BASE_NO 36
|
||||
|
||||
#else
|
||||
#define ERROR_BASE_NO 0
|
||||
#endif
|
||||
|
||||
#if defined(__ARMCC_VERSION) || defined(__IAR_SYSTEMS_ICC__)
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef EPERM
|
||||
#define EPERM (ERROR_BASE_NO + 1)
|
||||
#endif
|
||||
|
||||
#ifndef ENOENT
|
||||
#define ENOENT (ERROR_BASE_NO + 2)
|
||||
#endif
|
||||
|
||||
#ifndef ESRCH
|
||||
#define ESRCH (ERROR_BASE_NO + 3)
|
||||
#endif
|
||||
|
||||
#ifndef EINTR
|
||||
#define EINTR (ERROR_BASE_NO + 4)
|
||||
#endif
|
||||
|
||||
#ifndef EIO
|
||||
#define EIO (ERROR_BASE_NO + 5)
|
||||
#endif
|
||||
|
||||
#ifndef ENXIO
|
||||
#define ENXIO (ERROR_BASE_NO + 6)
|
||||
#endif
|
||||
|
||||
#ifndef E2BIG
|
||||
#define E2BIG (ERROR_BASE_NO + 7)
|
||||
#endif
|
||||
|
||||
#ifndef ENOEXEC
|
||||
#define ENOEXEC (ERROR_BASE_NO + 8)
|
||||
#endif
|
||||
|
||||
#ifndef EBADF
|
||||
#define EBADF (ERROR_BASE_NO + 9)
|
||||
#endif
|
||||
|
||||
#ifndef ECHILD
|
||||
#define ECHILD (ERROR_BASE_NO + 10)
|
||||
#endif
|
||||
|
||||
#ifndef EAGAIN
|
||||
#define EAGAIN (ERROR_BASE_NO + 11)
|
||||
#endif
|
||||
|
||||
#ifndef ENOMEM
|
||||
#define ENOMEM (ERROR_BASE_NO + 12)
|
||||
#endif
|
||||
|
||||
#ifndef EACCES
|
||||
#define EACCES (ERROR_BASE_NO + 13)
|
||||
#endif
|
||||
|
||||
#ifndef EFAULT
|
||||
#define EFAULT (ERROR_BASE_NO + 14)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTBLK
|
||||
#define ENOTBLK (ERROR_BASE_NO + 15)
|
||||
#endif
|
||||
|
||||
#ifndef EBUSY
|
||||
#define EBUSY (ERROR_BASE_NO + 16)
|
||||
#endif
|
||||
|
||||
#ifndef EEXIST
|
||||
#define EEXIST (ERROR_BASE_NO + 17)
|
||||
#endif
|
||||
|
||||
#ifndef EXDEV
|
||||
#define EXDEV (ERROR_BASE_NO + 18)
|
||||
#endif
|
||||
|
||||
#ifndef ENODEV
|
||||
#define ENODEV (ERROR_BASE_NO + 19)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTDIR
|
||||
#define ENOTDIR (ERROR_BASE_NO + 20)
|
||||
#endif
|
||||
|
||||
#ifndef EISDIR
|
||||
#define EISDIR (ERROR_BASE_NO + 21)
|
||||
#endif
|
||||
|
||||
#ifndef EINVAL
|
||||
#define EINVAL (ERROR_BASE_NO + 22)
|
||||
#endif
|
||||
|
||||
#ifndef ENFILE
|
||||
#define ENFILE (ERROR_BASE_NO + 23)
|
||||
#endif
|
||||
|
||||
#ifndef EMFILE
|
||||
#define EMFILE (ERROR_BASE_NO + 24)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTTY
|
||||
#define ENOTTY (ERROR_BASE_NO + 25)
|
||||
#endif
|
||||
|
||||
#ifndef ETXTBSY
|
||||
#define ETXTBSY (ERROR_BASE_NO + 26)
|
||||
#endif
|
||||
|
||||
#ifndef EFBIG
|
||||
#define EFBIG (ERROR_BASE_NO + 27)
|
||||
#endif
|
||||
|
||||
#ifndef ENOSPC
|
||||
#define ENOSPC (ERROR_BASE_NO + 28)
|
||||
#endif
|
||||
|
||||
#ifndef ESPIPE
|
||||
#define ESPIPE (ERROR_BASE_NO + 29)
|
||||
#endif
|
||||
|
||||
#ifndef EROFS
|
||||
#define EROFS (ERROR_BASE_NO + 30)
|
||||
#endif
|
||||
|
||||
#ifndef EMLINK
|
||||
#define EMLINK (ERROR_BASE_NO + 31)
|
||||
#endif
|
||||
|
||||
#ifndef EPIPE
|
||||
#define EPIPE (ERROR_BASE_NO + 32)
|
||||
#endif
|
||||
|
||||
#ifndef EDOM
|
||||
#define EDOM (ERROR_BASE_NO + 33)
|
||||
#endif
|
||||
|
||||
#ifndef ERANGE
|
||||
#define ERANGE (ERROR_BASE_NO + 34)
|
||||
#endif
|
||||
|
||||
#ifndef EDEADLK
|
||||
#define EDEADLK (ERROR_BASE_NO + 35)
|
||||
#endif
|
||||
|
||||
#ifndef ENAMETOOLONG
|
||||
#define ENAMETOOLONG (ERROR_BASE_NO + 36)
|
||||
#endif
|
||||
|
||||
#ifndef ENOLCK
|
||||
#define ENOLCK (ERROR_BASE_NO + 37)
|
||||
#endif
|
||||
|
||||
#ifndef ENOSYS
|
||||
#define ENOSYS (ERROR_BASE_NO + 38)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTEMPTY
|
||||
#define ENOTEMPTY (ERROR_BASE_NO + 39)
|
||||
#endif
|
||||
|
||||
#ifndef ELOOP
|
||||
#define ELOOP (ERROR_BASE_NO + 40)
|
||||
#endif
|
||||
|
||||
#ifndef EWOULDBLOCK
|
||||
#define EWOULDBLOCK EAGAIN
|
||||
#endif
|
||||
|
||||
#ifndef ENOMSG
|
||||
#define ENOMSG (ERROR_BASE_NO + 42)
|
||||
#endif
|
||||
|
||||
#ifndef EIDRM
|
||||
#define EIDRM (ERROR_BASE_NO + 43)
|
||||
#endif
|
||||
|
||||
#ifndef ECHRNG
|
||||
#define ECHRNG (ERROR_BASE_NO + 44)
|
||||
#endif
|
||||
|
||||
#ifndef EL2NSYNC
|
||||
#define EL2NSYNC (ERROR_BASE_NO + 45)
|
||||
#endif
|
||||
|
||||
#ifndef EL3HLT
|
||||
#define EL3HLT (ERROR_BASE_NO + 46)
|
||||
#endif
|
||||
|
||||
#ifndef EL3RST
|
||||
#define EL3RST (ERROR_BASE_NO + 47)
|
||||
#endif
|
||||
|
||||
#ifndef ELNRNG
|
||||
#define ELNRNG (ERROR_BASE_NO + 48)
|
||||
#endif
|
||||
|
||||
#ifndef EUNATCH
|
||||
#define EUNATCH (ERROR_BASE_NO + 49)
|
||||
#endif
|
||||
|
||||
#ifndef ENOCSI
|
||||
#define ENOCSI (ERROR_BASE_NO + 50)
|
||||
#endif
|
||||
|
||||
#ifndef EL2HLT
|
||||
#define EL2HLT (ERROR_BASE_NO + 51)
|
||||
#endif
|
||||
|
||||
#ifndef EBADE
|
||||
#define EBADE (ERROR_BASE_NO + 52)
|
||||
#endif
|
||||
|
||||
#ifndef EBADR
|
||||
#define EBADR (ERROR_BASE_NO + 53)
|
||||
#endif
|
||||
|
||||
#ifndef EXFULL
|
||||
#define EXFULL (ERROR_BASE_NO + 54)
|
||||
#endif
|
||||
|
||||
#ifndef ENOANO
|
||||
#define ENOANO (ERROR_BASE_NO + 55)
|
||||
#endif
|
||||
|
||||
#ifndef EBADRQC
|
||||
#define EBADRQC (ERROR_BASE_NO + 56)
|
||||
#endif
|
||||
|
||||
#ifndef EBADSLT
|
||||
#define EBADSLT (ERROR_BASE_NO + 57)
|
||||
#endif
|
||||
|
||||
#ifndef EDEADLOCK
|
||||
#define EDEADLOCK EDEADLK
|
||||
#endif
|
||||
|
||||
#ifndef EBFONT
|
||||
#define EBFONT (ERROR_BASE_NO + 59)
|
||||
#endif
|
||||
|
||||
#ifndef ENOSTR
|
||||
#define ENOSTR (ERROR_BASE_NO + 60)
|
||||
#endif
|
||||
|
||||
#ifndef ENODATA
|
||||
#define ENODATA (ERROR_BASE_NO + 61)
|
||||
#endif
|
||||
|
||||
#ifndef ETIME
|
||||
#define ETIME (ERROR_BASE_NO + 62)
|
||||
#endif
|
||||
|
||||
#ifndef ENOSR
|
||||
#define ENOSR (ERROR_BASE_NO + 63)
|
||||
#endif
|
||||
|
||||
#ifndef ENONET
|
||||
#define ENONET (ERROR_BASE_NO + 64)
|
||||
#endif
|
||||
|
||||
#ifndef ENOPKG
|
||||
#define ENOPKG (ERROR_BASE_NO + 65)
|
||||
#endif
|
||||
|
||||
#ifndef EREMOTE
|
||||
#define EREMOTE (ERROR_BASE_NO + 66)
|
||||
#endif
|
||||
|
||||
#ifndef ENOLINK
|
||||
#define ENOLINK (ERROR_BASE_NO + 67)
|
||||
#endif
|
||||
|
||||
#ifndef EADV
|
||||
#define EADV (ERROR_BASE_NO + 68)
|
||||
#endif
|
||||
|
||||
#ifndef ESRMNT
|
||||
#define ESRMNT (ERROR_BASE_NO + 69)
|
||||
#endif
|
||||
|
||||
#ifndef ECOMM
|
||||
#define ECOMM (ERROR_BASE_NO + 70)
|
||||
#endif
|
||||
|
||||
#ifndef EPROTO
|
||||
#define EPROTO (ERROR_BASE_NO + 71)
|
||||
#endif
|
||||
|
||||
#ifndef EMULTIHOP
|
||||
#define EMULTIHOP (ERROR_BASE_NO + 72)
|
||||
#endif
|
||||
|
||||
#ifndef EDOTDOT
|
||||
#define EDOTDOT (ERROR_BASE_NO + 73)
|
||||
#endif
|
||||
|
||||
#ifndef EBADMSG
|
||||
#define EBADMSG (ERROR_BASE_NO + 74)
|
||||
#endif
|
||||
|
||||
#ifndef EOVERFLOW
|
||||
#define EOVERFLOW (ERROR_BASE_NO + 75)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTUNIQ
|
||||
#define ENOTUNIQ (ERROR_BASE_NO + 76)
|
||||
#endif
|
||||
|
||||
#ifndef EBADFD
|
||||
#define EBADFD (ERROR_BASE_NO + 77)
|
||||
#endif
|
||||
|
||||
#ifndef EREMCHG
|
||||
#define EREMCHG (ERROR_BASE_NO + 78)
|
||||
#endif
|
||||
|
||||
#ifndef ELIBACC
|
||||
#define ELIBACC (ERROR_BASE_NO + 79)
|
||||
#endif
|
||||
|
||||
#ifndef ELIBBAD
|
||||
#define ELIBBAD (ERROR_BASE_NO + 80)
|
||||
#endif
|
||||
|
||||
#ifndef ELIBSCN
|
||||
#define ELIBSCN (ERROR_BASE_NO + 81)
|
||||
#endif
|
||||
|
||||
#ifndef ELIBMAX
|
||||
#define ELIBMAX (ERROR_BASE_NO + 82)
|
||||
#endif
|
||||
|
||||
#ifndef ELIBEXEC
|
||||
#define ELIBEXEC (ERROR_BASE_NO + 83)
|
||||
#endif
|
||||
|
||||
#ifndef EILSEQ
|
||||
#define EILSEQ (ERROR_BASE_NO + 84)
|
||||
#endif
|
||||
|
||||
#ifndef ERESTART
|
||||
#define ERESTART (ERROR_BASE_NO + 85)
|
||||
#endif
|
||||
|
||||
#ifndef ESTRPIPE
|
||||
#define ESTRPIPE (ERROR_BASE_NO + 86)
|
||||
#endif
|
||||
|
||||
#ifndef EUSERS
|
||||
#define EUSERS (ERROR_BASE_NO + 87)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTSOCK
|
||||
#define ENOTSOCK (ERROR_BASE_NO + 88)
|
||||
#endif
|
||||
|
||||
#ifndef EDESTADDRREQ
|
||||
#define EDESTADDRREQ (ERROR_BASE_NO + 89)
|
||||
#endif
|
||||
|
||||
#ifndef EMSGSIZE
|
||||
#define EMSGSIZE (ERROR_BASE_NO + 90)
|
||||
#endif
|
||||
|
||||
#ifndef EPROTOTYPE
|
||||
#define EPROTOTYPE (ERROR_BASE_NO + 91)
|
||||
#endif
|
||||
|
||||
#ifndef ENOPROTOOPT
|
||||
#define ENOPROTOOPT (ERROR_BASE_NO + 92)
|
||||
#endif
|
||||
|
||||
#ifndef EPROTONOSUPPORT
|
||||
#define EPROTONOSUPPORT (ERROR_BASE_NO + 93)
|
||||
#endif
|
||||
|
||||
#ifndef ESOCKTNOSUPPORT
|
||||
#define ESOCKTNOSUPPORT (ERROR_BASE_NO + 94)
|
||||
#endif
|
||||
|
||||
#ifndef EOPNOTSUPP
|
||||
#define EOPNOTSUPP (ERROR_BASE_NO + 95)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTSUP
|
||||
#define ENOTSUP EOPNOTSUPP
|
||||
#endif
|
||||
|
||||
#ifndef EPFNOSUPPORT
|
||||
#define EPFNOSUPPORT (ERROR_BASE_NO + 96)
|
||||
#endif
|
||||
|
||||
#ifndef EAFNOSUPPORT
|
||||
#define EAFNOSUPPORT (ERROR_BASE_NO + 97)
|
||||
#endif
|
||||
|
||||
#ifndef EADDRINUSE
|
||||
#define EADDRINUSE (ERROR_BASE_NO + 98)
|
||||
#endif
|
||||
|
||||
#ifndef EADDRNOTAVAIL
|
||||
#define EADDRNOTAVAIL (ERROR_BASE_NO + 99)
|
||||
#endif
|
||||
|
||||
#ifndef ENETDOWN
|
||||
#define ENETDOWN (ERROR_BASE_NO + 100)
|
||||
#endif
|
||||
|
||||
#ifndef ENETUNREACH
|
||||
#define ENETUNREACH (ERROR_BASE_NO + 101)
|
||||
#endif
|
||||
|
||||
#ifndef ENETRESET
|
||||
#define ENETRESET (ERROR_BASE_NO + 102)
|
||||
#endif
|
||||
|
||||
#ifndef ECONNABORTED
|
||||
#define ECONNABORTED (ERROR_BASE_NO + 103)
|
||||
#endif
|
||||
|
||||
#ifndef ECONNRESET
|
||||
#define ECONNRESET (ERROR_BASE_NO + 104)
|
||||
#endif
|
||||
|
||||
#ifndef ENOBUFS
|
||||
#define ENOBUFS (ERROR_BASE_NO + 105)
|
||||
#endif
|
||||
|
||||
#ifndef EISCONN
|
||||
#define EISCONN (ERROR_BASE_NO + 106)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTCONN
|
||||
#define ENOTCONN (ERROR_BASE_NO + 107)
|
||||
#endif
|
||||
|
||||
#ifndef ESHUTDOWN
|
||||
#define ESHUTDOWN (ERROR_BASE_NO + 108)
|
||||
#endif
|
||||
|
||||
#ifndef ETOOMANYREFS
|
||||
#define ETOOMANYREFS (ERROR_BASE_NO + 109)
|
||||
#endif
|
||||
|
||||
#ifndef ETIMEDOUT
|
||||
#define ETIMEDOUT (ERROR_BASE_NO + 110)
|
||||
#endif
|
||||
|
||||
#ifndef ECONNREFUSED
|
||||
#define ECONNREFUSED (ERROR_BASE_NO + 111)
|
||||
#endif
|
||||
|
||||
#ifndef EHOSTDOWN
|
||||
#define EHOSTDOWN (ERROR_BASE_NO + 112)
|
||||
#endif
|
||||
|
||||
#ifndef EHOSTUNREACH
|
||||
#define EHOSTUNREACH (ERROR_BASE_NO + 113)
|
||||
#endif
|
||||
|
||||
#ifndef EALREADY
|
||||
#define EALREADY (ERROR_BASE_NO + 114)
|
||||
#endif
|
||||
|
||||
#ifndef EINPROGRESS
|
||||
#define EINPROGRESS (ERROR_BASE_NO + 115)
|
||||
#endif
|
||||
|
||||
#ifndef ESTALE
|
||||
#define ESTALE (ERROR_BASE_NO + 116)
|
||||
#endif
|
||||
|
||||
#ifndef EUCLEAN
|
||||
#define EUCLEAN (ERROR_BASE_NO + 117)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTNAM
|
||||
#define ENOTNAM (ERROR_BASE_NO + 118)
|
||||
#endif
|
||||
|
||||
#ifndef ENAVAIL
|
||||
#define ENAVAIL (ERROR_BASE_NO + 119)
|
||||
#endif
|
||||
|
||||
#ifndef EISNAM
|
||||
#define EISNAM (ERROR_BASE_NO + 120)
|
||||
#endif
|
||||
|
||||
#ifndef EREMOTEIO
|
||||
#define EREMOTEIO (ERROR_BASE_NO + 121)
|
||||
#endif
|
||||
|
||||
#ifndef EDQUOT
|
||||
#define EDQUOT (ERROR_BASE_NO + 122)
|
||||
#endif
|
||||
|
||||
#ifndef ENOMEDIUM
|
||||
#define ENOMEDIUM (ERROR_BASE_NO + 123)
|
||||
#endif
|
||||
|
||||
#ifndef EMEDIUMTYPE
|
||||
#define EMEDIUMTYPE (ERROR_BASE_NO + 124)
|
||||
#endif
|
||||
|
||||
#ifndef ECANCELED
|
||||
#define ECANCELED (ERROR_BASE_NO + 125)
|
||||
#endif
|
||||
|
||||
#ifndef ENOKEY
|
||||
#define ENOKEY (ERROR_BASE_NO + 126)
|
||||
#endif
|
||||
|
||||
#ifndef EKEYEXPIRED
|
||||
#define EKEYEXPIRED (ERROR_BASE_NO + 127)
|
||||
#endif
|
||||
|
||||
#ifndef EKEYREVOKED
|
||||
#define EKEYREVOKED (ERROR_BASE_NO + 128)
|
||||
#endif
|
||||
|
||||
#ifndef EKEYREJECTED
|
||||
#define EKEYREJECTED (ERROR_BASE_NO + 129)
|
||||
#endif
|
||||
|
||||
#ifndef EOWNERDEAD
|
||||
#define EOWNERDEAD (ERROR_BASE_NO + 130)
|
||||
#endif
|
||||
|
||||
#ifndef ENOTRECOVERABLE
|
||||
#define ENOTRECOVERABLE (ERROR_BASE_NO + 131)
|
||||
#endif
|
||||
|
||||
#ifndef ERFKILL
|
||||
#define ERFKILL (ERROR_BASE_NO + 132)
|
||||
#endif
|
||||
|
||||
#ifndef EHWPOISON
|
||||
#define EHWPOISON (ERROR_BASE_NO + 133)
|
||||
#endif
|
||||
|
||||
#elif defined(_WIN32)
|
||||
#include <errno.h>
|
||||
|
||||
#endif /* defined(__ARMCC_VERSION) || defined(__IAR_SYSTEMS_ICC__) */
|
||||
|
||||
#endif /* __SYS_ERRNO_H__ */
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-07-21 Meco Man The first version
|
||||
* 2021-12-25 Meco Man Handle newlib 2.2.0 or lower version
|
||||
*/
|
||||
|
||||
#ifndef __SYS_SELECT_H__
|
||||
#define __SYS_SELECT_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#ifndef FD_SETSIZE
|
||||
#define FD_SETSIZE 32
|
||||
#endif
|
||||
|
||||
#ifdef SAL_USING_POSIX
|
||||
#ifdef FD_SETSIZE
|
||||
#undef FD_SETSIZE
|
||||
#endif
|
||||
#define FD_SETSIZE DFS_FD_MAX
|
||||
#endif /* SAL_USING_POSIX */
|
||||
|
||||
typedef long fd_mask;
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef _SYS_TYPES_FD_SET /* Newlib 2.2.0 or lower version */
|
||||
#define NBBY 8 /* number of bits in a byte */
|
||||
#define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */
|
||||
#ifndef howmany
|
||||
#define howmany(x,y) (((x)+((y)-1))/(y))
|
||||
#endif /* howmany */
|
||||
|
||||
typedef struct _types_fd_set {
|
||||
fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
|
||||
} _types_fd_set;
|
||||
#define fd_set _types_fd_set
|
||||
|
||||
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS)))
|
||||
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS)))
|
||||
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS)))
|
||||
#define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p)))
|
||||
#endif /* _SYS_TYPES_FD_SET */
|
||||
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* __SYS_SELECT_H__ */
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-02 Meco Man First version
|
||||
*/
|
||||
|
||||
#ifndef __SYS_STAT_H__
|
||||
#define __SYS_STAT_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define S_IFMT 00170000
|
||||
#define S_IFSOCK 0140000
|
||||
#define S_IFLNK 0120000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IFBLK 0060000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_IFCHR 0020000
|
||||
#define S_IFIFO 0010000
|
||||
#define S_ISUID 0004000
|
||||
#define S_ISGID 0002000
|
||||
#define S_ISVTX 0001000
|
||||
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
||||
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
|
||||
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
|
||||
#define S_IRWXU 00700
|
||||
#define S_IRUSR 00400
|
||||
#define S_IWUSR 00200
|
||||
#define S_IXUSR 00100
|
||||
|
||||
#define S_IRWXG 00070
|
||||
#define S_IRGRP 00040
|
||||
#define S_IWGRP 00020
|
||||
#define S_IXGRP 00010
|
||||
|
||||
#define S_IRWXO 00007
|
||||
#define S_IROTH 00004
|
||||
#define S_IWOTH 00002
|
||||
#define S_IXOTH 00001
|
||||
|
||||
struct stat
|
||||
{
|
||||
struct rt_device *st_dev;
|
||||
uint16_t st_ino;
|
||||
uint16_t st_mode;
|
||||
uint16_t st_nlink;
|
||||
uint16_t st_uid;
|
||||
uint16_t st_gid;
|
||||
struct rt_device *st_rdev;
|
||||
uint32_t st_size;
|
||||
time_t st_atime;
|
||||
long st_spare1;
|
||||
time_t st_mtime;
|
||||
long st_spare2;
|
||||
time_t st_ctime;
|
||||
long st_spare3;
|
||||
uint32_t st_blksize;
|
||||
uint32_t st_blocks;
|
||||
long st_spare4[2];
|
||||
};
|
||||
|
||||
int chmod(const char *, mode_t);
|
||||
int fchmod(int, mode_t);
|
||||
int fstat(int, struct stat *);
|
||||
int lstat(const char *, struct stat *);
|
||||
int mkdir(const char *, mode_t);
|
||||
int mkfifo(const char *, mode_t);
|
||||
int mknod(const char *, mode_t, dev_t);
|
||||
int stat(const char *, struct stat *);
|
||||
mode_t umask(mode_t);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-09-05 Meco Man fix bugs
|
||||
* 2020-12-16 Meco Man add useconds_t
|
||||
*/
|
||||
|
||||
#ifndef __SYS_TYPES_H__
|
||||
#define __SYS_TYPES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef int32_t clockid_t;
|
||||
typedef int32_t key_t; /* Used for interprocess communication. */
|
||||
typedef int pid_t; /* Used for process IDs and process group IDs. */
|
||||
typedef unsigned short uid_t;
|
||||
typedef unsigned short gid_t;
|
||||
typedef signed long off_t;
|
||||
typedef int mode_t;
|
||||
#ifndef ARCH_CPU_64BIT
|
||||
typedef signed int ssize_t; /* Used for a count of bytes or an error indication. */
|
||||
#else
|
||||
typedef long signed int ssize_t; /* Used for a count of bytes or an error indication. */
|
||||
#endif
|
||||
typedef unsigned long __timer_t;
|
||||
typedef __timer_t timer_t;
|
||||
typedef long suseconds_t; /* microseconds. */
|
||||
typedef unsigned long useconds_t; /* microseconds (unsigned) */
|
||||
|
||||
typedef unsigned long dev_t;
|
||||
|
||||
typedef unsigned int u_int;
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned long u_long;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-12-16 Meco Man add usleep
|
||||
* 2021-09-11 Meco Man move functions from dfs_posix.h to unistd.h
|
||||
*/
|
||||
|
||||
#ifndef __SYS_UNISTD_H__
|
||||
#define __SYS_UNISTD_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include "types.h" /* <sys/types.h> */
|
||||
|
||||
#define STDIN_FILENO 0 /* standard input file descriptor */
|
||||
#define STDOUT_FILENO 1 /* standard output file descriptor */
|
||||
#define STDERR_FILENO 2 /* standard error file descriptor */
|
||||
|
||||
unsigned alarm(unsigned __secs);
|
||||
ssize_t read(int fd, void *buf, size_t len);
|
||||
ssize_t write(int fd, const void *buf, size_t len);
|
||||
off_t lseek(int fd, off_t offset, int whence);
|
||||
int pause(void);
|
||||
int fsync(int fildes);
|
||||
long sysconf(int __name);
|
||||
int unlink(const char *pathname);
|
||||
int close(int d);
|
||||
int ftruncate(int fd, off_t length);
|
||||
int rmdir(const char *path);
|
||||
int chdir(const char *path);
|
||||
char *getcwd(char *buf, size_t size);
|
||||
int access(const char *path, int amode);
|
||||
int pipe(int fildes[2]);
|
||||
int isatty(int fd);
|
||||
char *ttyname(int desc);
|
||||
unsigned int sleep(unsigned int seconds);
|
||||
int usleep(useconds_t usec);
|
||||
pid_t gettid(void);
|
||||
pid_t getpid(void);
|
||||
pid_t getppid(void);
|
||||
uid_t getuid(void);
|
||||
uid_t geteuid(void);
|
||||
gid_t getgid(void);
|
||||
gid_t getegid(void);
|
||||
|
||||
#endif /* _SYS_UNISTD_H */
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "sys/unistd.h"
|
||||
@@ -0,0 +1 @@
|
||||
This folder is "common" for all toolchains.
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-02-15 Meco Man first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define DBG_TAG "stdlib"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
void __rt_libc_exit(int status)
|
||||
{
|
||||
rt_thread_t self = rt_thread_self();
|
||||
|
||||
if (self != RT_NULL)
|
||||
{
|
||||
LOG_E("thread:%s exit:%d!", self->name, status);
|
||||
rt_thread_control(self, RT_THREAD_CTRL_CLOSE, RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_MSH
|
||||
int system(const char *command)
|
||||
{
|
||||
extern int msh_exec(char *cmd, rt_size_t length);
|
||||
|
||||
int ret = -RT_ENOMEM;
|
||||
char *cmd = rt_strdup(command);
|
||||
|
||||
if (cmd)
|
||||
{
|
||||
ret = msh_exec(cmd, rt_strlen(cmd));
|
||||
rt_free(cmd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
RTM_EXPORT(system);
|
||||
#endif
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-09-01 Meco Man First Version
|
||||
*/
|
||||
|
||||
#ifndef __SYS_IOCTL_H__
|
||||
#define __SYS_IOCTL_H__
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
struct winsize
|
||||
{
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_col;
|
||||
unsigned short ws_xpixel;
|
||||
unsigned short ws_ypixel;
|
||||
};
|
||||
|
||||
/*
|
||||
* Direction bits, which any architecture can choose to override
|
||||
* before including this file.
|
||||
*/
|
||||
|
||||
#ifndef _IOC_NONE
|
||||
#define _IOC_NONE 0U
|
||||
#endif
|
||||
|
||||
#ifndef _IOC_WRITE
|
||||
#define _IOC_WRITE 1U
|
||||
#endif
|
||||
|
||||
#ifndef _IOC_READ
|
||||
#define _IOC_READ 2U
|
||||
#endif
|
||||
|
||||
#ifndef _IOC
|
||||
#define _IOC(a,b,c,d) (((a)<<30) | ((b)<<8) | (c) | ((d)<<16))
|
||||
#endif
|
||||
|
||||
#ifndef _IO
|
||||
#define _IO(a,b) _IOC(_IOC_NONE, (a), (b), 0)
|
||||
#endif
|
||||
|
||||
#ifndef _IOW
|
||||
#define _IOW(a,b,c) _IOC(_IOC_WRITE, (a), (b), sizeof(c))
|
||||
#endif
|
||||
|
||||
#ifndef _IOR
|
||||
#define _IOR(a,b,c) _IOC(_IOC_READ, (a), (b), sizeof(c))
|
||||
#endif
|
||||
|
||||
#ifndef _IOWR
|
||||
#define _IOWR(a,b,c) _IOC(_IOC_READ|_IOC_WRITE, (a), (b), sizeof(c))
|
||||
#endif
|
||||
|
||||
#ifndef FIONREAD
|
||||
#define FIONREAD _IOR('f', 127, int) /* get # bytes to read */
|
||||
#endif
|
||||
|
||||
#ifndef FIONBIO
|
||||
#define FIONBIO _IOW('f', 126, int) /* set/clear non-blocking i/o */
|
||||
#endif
|
||||
|
||||
#ifndef FIOASYNC
|
||||
#define FIOASYNC _IOW('f', 125, int) /* set/clear async i/o */
|
||||
#endif
|
||||
|
||||
#ifndef FIONWRITE
|
||||
#define FIONWRITE _IOR('f', 121, int) /* get # bytes outstanding in send queue */
|
||||
#endif
|
||||
|
||||
/* Socket I/O Controls */
|
||||
#ifndef SIOCSHIWAT
|
||||
#define SIOCSHIWAT _IOW('s', 0, int) /* set high watermark */
|
||||
#define SIOCGHIWAT _IOR('s', 1, int) /* get high watermark */
|
||||
#define SIOCSLOWAT _IOW('s', 2, int) /* set low watermark */
|
||||
#define SIOCGLOWAT _IOR('s', 3, int) /* get low watermark */
|
||||
#define SIOCATMARK _IOR('s', 7, int) /* at oob mark? */
|
||||
#endif
|
||||
|
||||
#define TCGETS 0x5401
|
||||
#define TCSETS 0x5402
|
||||
#define TCSETSW 0x5403
|
||||
#define TCSETSF 0x5404
|
||||
#define TCGETA 0x5405
|
||||
#define TCSETA 0x5406
|
||||
#define TCSETAW 0x5407
|
||||
#define TCSETAF 0x5408
|
||||
#define TCSBRK 0x5409
|
||||
#define TCXONC 0x540A
|
||||
#define TCFLSH 0x540B
|
||||
#define TIOCEXCL 0x540C
|
||||
#define TIOCNXCL 0x540D
|
||||
#define TIOCSCTTY 0x540E
|
||||
#define TIOCGPGRP 0x540F
|
||||
#define TIOCSPGRP 0x5410
|
||||
#define TIOCOUTQ 0x5411
|
||||
#define TIOCSTI 0x5412
|
||||
#define TIOCGWINSZ 0x5413
|
||||
#define TIOCSWINSZ 0x5414
|
||||
#define TIOCMGET 0x5415
|
||||
#define TIOCMBIS 0x5416
|
||||
#define TIOCMBIC 0x5417
|
||||
#define TIOCMSET 0x5418
|
||||
#define TIOCGSOFTCAR 0x5419
|
||||
#define TIOCSSOFTCAR 0x541A
|
||||
#define TIOCINQ FIONREAD
|
||||
#define TIOCLINUX 0x541C
|
||||
#define TIOCCONS 0x541D
|
||||
#define TIOCGSERIAL 0x541E
|
||||
#define TIOCSSERIAL 0x541F
|
||||
#define TIOCPKT 0x5420
|
||||
#define TIOCNOTTY 0x5422
|
||||
#define TIOCSETD 0x5423
|
||||
#define TIOCGETD 0x5424
|
||||
#define TCSBRKP 0x5425
|
||||
#define TIOCSBRK 0x5427
|
||||
#define TIOCCBRK 0x5428
|
||||
#define TIOCGSID 0x5429
|
||||
#define TIOCGRS485 0x542E
|
||||
#define TIOCSRS485 0x542F
|
||||
#define TIOCGPTN 0x80045430
|
||||
#define TIOCSPTLCK 0x40045431
|
||||
#define TIOCGDEV 0x80045432
|
||||
#define TCGETX 0x5432
|
||||
#define TCSETX 0x5433
|
||||
#define TCSETXF 0x5434
|
||||
#define TCSETXW 0x5435
|
||||
#define TIOCSIG 0x40045436
|
||||
#define TIOCVHANGUP 0x5437
|
||||
#define TIOCGPKT 0x80045438
|
||||
#define TIOCGPTLCK 0x80045439
|
||||
#define TIOCGEXCL 0x80045440
|
||||
|
||||
#define FIONCLEX 0x5450
|
||||
#define FIOCLEX 0x5451
|
||||
|
||||
#define TIOCSERCONFIG 0x5453
|
||||
#define TIOCSERGWILD 0x5454
|
||||
#define TIOCSERSWILD 0x5455
|
||||
#define TIOCGLCKTRMIOS 0x5456
|
||||
#define TIOCSLCKTRMIOS 0x5457
|
||||
#define TIOCSERGSTRUCT 0x5458
|
||||
#define TIOCSERGETLSR 0x5459
|
||||
#define TIOCSERGETMULTI 0x545A
|
||||
#define TIOCSERSETMULTI 0x545B
|
||||
|
||||
#define TIOCMIWAIT 0x545C
|
||||
#define TIOCGICOUNT 0x545D
|
||||
#define FIOQSIZE 0x5460
|
||||
|
||||
#define TIOCPKT_DATA 0
|
||||
#define TIOCPKT_FLUSHREAD 1
|
||||
#define TIOCPKT_FLUSHWRITE 2
|
||||
#define TIOCPKT_STOP 4
|
||||
#define TIOCPKT_START 8
|
||||
#define TIOCPKT_NOSTOP 16
|
||||
#define TIOCPKT_DOSTOP 32
|
||||
#define TIOCPKT_IOCTL 64
|
||||
|
||||
#define TIOCSER_TEMT 0x01
|
||||
|
||||
#define TIOCM_LE 0x001
|
||||
#define TIOCM_DTR 0x002
|
||||
#define TIOCM_RTS 0x004
|
||||
#define TIOCM_ST 0x008
|
||||
#define TIOCM_SR 0x010
|
||||
#define TIOCM_CTS 0x020
|
||||
#define TIOCM_CAR 0x040
|
||||
#define TIOCM_RNG 0x080
|
||||
#define TIOCM_DSR 0x100
|
||||
#define TIOCM_CD TIOCM_CAR
|
||||
#define TIOCM_RI TIOCM_RNG
|
||||
#define TIOCM_OUT1 0x2000
|
||||
#define TIOCM_OUT2 0x4000
|
||||
#define TIOCM_LOOP 0x8000
|
||||
|
||||
#define N_TTY 0
|
||||
#define N_SLIP 1
|
||||
#define N_MOUSE 2
|
||||
#define N_PPP 3
|
||||
#define N_STRIP 4
|
||||
#define N_AX25 5
|
||||
#define N_X25 6
|
||||
#define N_6PACK 7
|
||||
#define N_MASC 8
|
||||
#define N_R3964 9
|
||||
#define N_PROFIBUS_FDL 10
|
||||
#define N_IRDA 11
|
||||
#define N_SMSBLOCK 12
|
||||
#define N_HDLC 13
|
||||
#define N_SYNC_PPP 14
|
||||
#define N_HCI 15
|
||||
|
||||
#define FIOSETOWN 0x8901
|
||||
#define SIOCSPGRP 0x8902
|
||||
#define FIOGETOWN 0x8903
|
||||
#define SIOCGPGRP 0x8904
|
||||
#define SIOCGSTAMP 0x8906
|
||||
#define SIOCGSTAMPNS 0x8907
|
||||
|
||||
#define SIOCADDRT 0x890B
|
||||
#define SIOCDELRT 0x890C
|
||||
#define SIOCRTMSG 0x890D
|
||||
|
||||
#define SIOCGIFNAME 0x8910
|
||||
#define SIOCSIFLINK 0x8911
|
||||
#define SIOCGIFCONF 0x8912
|
||||
#define SIOCGIFFLAGS 0x8913
|
||||
#define SIOCSIFFLAGS 0x8914
|
||||
#define SIOCGIFADDR 0x8915
|
||||
#define SIOCSIFADDR 0x8916
|
||||
#define SIOCGIFDSTADDR 0x8917
|
||||
#define SIOCSIFDSTADDR 0x8918
|
||||
#define SIOCGIFBRDADDR 0x8919
|
||||
#define SIOCSIFBRDADDR 0x891a
|
||||
#define SIOCGIFNETMASK 0x891b
|
||||
#define SIOCSIFNETMASK 0x891c
|
||||
#define SIOCGIFMETRIC 0x891d
|
||||
#define SIOCSIFMETRIC 0x891e
|
||||
#define SIOCGIFMEM 0x891f
|
||||
#define SIOCSIFMEM 0x8920
|
||||
#define SIOCGIFMTU 0x8921
|
||||
#define SIOCSIFMTU 0x8922
|
||||
#define SIOCSIFNAME 0x8923
|
||||
#define SIOCSIFHWADDR 0x8924
|
||||
#define SIOCGIFENCAP 0x8925
|
||||
#define SIOCSIFENCAP 0x8926
|
||||
#define SIOCGIFHWADDR 0x8927
|
||||
#define SIOCGIFSLAVE 0x8929
|
||||
#define SIOCSIFSLAVE 0x8930
|
||||
#define SIOCADDMULTI 0x8931
|
||||
#define SIOCDELMULTI 0x8932
|
||||
#define SIOCGIFINDEX 0x8933
|
||||
#define SIOGIFINDEX SIOCGIFINDEX
|
||||
#define SIOCSIFPFLAGS 0x8934
|
||||
#define SIOCGIFPFLAGS 0x8935
|
||||
#define SIOCDIFADDR 0x8936
|
||||
#define SIOCSIFHWBROADCAST 0x8937
|
||||
#define SIOCGIFCOUNT 0x8938
|
||||
|
||||
#define SIOCGIFBR 0x8940
|
||||
#define SIOCSIFBR 0x8941
|
||||
|
||||
#define SIOCGIFTXQLEN 0x8942
|
||||
#define SIOCSIFTXQLEN 0x8943
|
||||
|
||||
#define SIOCDARP 0x8953
|
||||
#define SIOCGARP 0x8954
|
||||
#define SIOCSARP 0x8955
|
||||
|
||||
#define SIOCDRARP 0x8960
|
||||
#define SIOCGRARP 0x8961
|
||||
#define SIOCSRARP 0x8962
|
||||
|
||||
#define SIOCGIFMAP 0x8970
|
||||
#define SIOCSIFMAP 0x8971
|
||||
|
||||
#define SIOCADDDLCI 0x8980
|
||||
#define SIOCDELDLCI 0x8981
|
||||
|
||||
#define SIOCDEVPRIVATE 0x89F0
|
||||
#define SIOCPROTOPRIVATE 0x89E0
|
||||
|
||||
int ioctl(int fildes, int cmd, ...);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-09-12 Bernard The first version
|
||||
* 2021-07-21 Meco Man move to libc/common
|
||||
*/
|
||||
|
||||
#ifndef __SYS_SIGNAL_H__
|
||||
#define __SYS_SIGNAL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/* sigev_notify values
|
||||
NOTE: P1003.1c/D10, p. 34 adds SIGEV_THREAD. */
|
||||
|
||||
#define SIGEV_NONE 1 /* No asynchronous notification shall be delivered */
|
||||
/* when the event of interest occurs. */
|
||||
#define SIGEV_SIGNAL 2 /* A queued signal, with an application defined */
|
||||
/* value, shall be delivered when the event of */
|
||||
/* interest occurs. */
|
||||
#define SIGEV_THREAD 3 /* A notification function shall be called to */
|
||||
/* perform notification. */
|
||||
|
||||
/* Signal Generation and Delivery, P1003.1b-1993, p. 63
|
||||
NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and
|
||||
sigev_notify_attributes to the sigevent structure. */
|
||||
union sigval
|
||||
{
|
||||
int sival_int; /* Integer signal value */
|
||||
void *sival_ptr; /* Pointer signal value */
|
||||
};
|
||||
|
||||
struct sigevent
|
||||
{
|
||||
int sigev_notify; /* Notification type */
|
||||
int sigev_signo; /* Signal number */
|
||||
union sigval sigev_value; /* Signal value */
|
||||
void (*sigev_notify_function)( union sigval );
|
||||
/* Notification function */
|
||||
void *sigev_notify_attributes; /* Notification Attributes, really pthread_attr_t */
|
||||
};
|
||||
|
||||
struct siginfo
|
||||
{
|
||||
uint16_t si_signo;
|
||||
uint16_t si_code;
|
||||
|
||||
union sigval si_value;
|
||||
};
|
||||
typedef struct siginfo siginfo_t;
|
||||
|
||||
#define SI_USER 0x01 /* Signal sent by kill(). */
|
||||
#define SI_QUEUE 0x02 /* Signal sent by sigqueue(). */
|
||||
#define SI_TIMER 0x03 /* Signal generated by expiration of a timer set by timer_settime(). */
|
||||
#define SI_ASYNCIO 0x04 /* Signal generated by completion of an asynchronous I/O request. */
|
||||
#define SI_MESGQ 0x05 /* Signal generated by arrival of a message on an empty message queue. */
|
||||
|
||||
typedef void (*_sig_func_ptr)(int);
|
||||
typedef unsigned long sigset_t;
|
||||
|
||||
struct sigaction
|
||||
{
|
||||
_sig_func_ptr sa_handler;
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure used in sigaltstack call.
|
||||
*/
|
||||
typedef struct sigaltstack
|
||||
{
|
||||
void *ss_sp; /* Stack base or pointer. */
|
||||
int ss_flags; /* Flags. */
|
||||
size_t ss_size; /* Stack size. */
|
||||
} stack_t;
|
||||
|
||||
#define SIG_SETMASK 0 /* set mask with sigprocmask() */
|
||||
#define SIG_BLOCK 1 /* set of signals to block */
|
||||
#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */
|
||||
|
||||
#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0)
|
||||
#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0)
|
||||
#define sigemptyset(what) (*(what) = 0, 0)
|
||||
#define sigfillset(what) (*(what) = ~(0), 0)
|
||||
#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0)
|
||||
|
||||
int sigprocmask (int how, const sigset_t *set, sigset_t *oset);
|
||||
int sigpending (sigset_t *set);
|
||||
int sigsuspend (const sigset_t *set);
|
||||
|
||||
#include "time.h"
|
||||
int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout);
|
||||
int sigwait(const sigset_t *set, int *sig);
|
||||
int sigwaitinfo(const sigset_t *set, siginfo_t *info);
|
||||
int raise(int sig);
|
||||
int sigqueue(pid_t pid, int signo, const union sigval value);
|
||||
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
|
||||
|
||||
#ifdef __ARMCC_VERSION
|
||||
#define SIGHUP 1
|
||||
/* #define SIGINT 2 */
|
||||
#define SIGQUIT 3
|
||||
/* #define SIGILL 4 */
|
||||
#define SIGTRAP 5
|
||||
/* #define SIGABRT 6 */
|
||||
#define SIGEMT 7
|
||||
/* #define SIGFPE 8 */
|
||||
#define SIGKILL 9
|
||||
#define SIGBUS 10
|
||||
/* #define SIGSEGV 11 */
|
||||
#define SIGSYS 12
|
||||
#define SIGPIPE 13
|
||||
#define SIGALRM 14
|
||||
/* #define SIGTERM 15 */
|
||||
#define SIGURG 16
|
||||
#define SIGSTOP 17
|
||||
#define SIGTSTP 18
|
||||
#define SIGCONT 19
|
||||
#define SIGCHLD 20
|
||||
#define SIGTTIN 21
|
||||
#define SIGTTOU 22
|
||||
#define SIGPOLL 23
|
||||
#define SIGWINCH 24
|
||||
#define SIGXCPU 24 /* exceeded CPU time limit */
|
||||
#define SIGXFSZ 25 /* exceeded file size limit */
|
||||
#define SIGVTALRM 26 /* virtual time alarm */
|
||||
/* #define SIGUSR1 25 */
|
||||
/* #define SIGUSR2 26 */
|
||||
#define SIGRTMIN 27
|
||||
#define SIGRTMAX 31
|
||||
#define NSIG 32
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
#define SIGHUP 1
|
||||
#define SIGINT 2
|
||||
#define SIGQUIT 3
|
||||
#define SIGILL 4
|
||||
#define SIGTRAP 5
|
||||
/* #define SIGABRT 6 */
|
||||
#define SIGEMT 7
|
||||
#define SIGFPE 8
|
||||
#define SIGKILL 9
|
||||
#define SIGBUS 10
|
||||
#define SIGSEGV 11
|
||||
#define SIGSYS 12
|
||||
#define SIGPIPE 13
|
||||
#define SIGALRM 14
|
||||
#define SIGTERM 15
|
||||
#define SIGURG 16
|
||||
#define SIGSTOP 17
|
||||
#define SIGTSTP 18
|
||||
#define SIGCONT 19
|
||||
#define SIGCHLD 20
|
||||
#define SIGTTIN 21
|
||||
#define SIGTTOU 22
|
||||
#define SIGPOLL 23
|
||||
#define SIGWINCH 24
|
||||
#define SIGXCPU 24 /* exceeded CPU time limit */
|
||||
#define SIGXFSZ 25 /* exceeded file size limit */
|
||||
#define SIGVTALRM 26 /* virtual time alarm */
|
||||
#define SIGUSR1 25
|
||||
#define SIGUSR2 26
|
||||
#define SIGRTMIN 27
|
||||
#define SIGRTMAX 31
|
||||
#define NSIG 32
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
#define SIGHUP 1 /* hangup */
|
||||
#define SIGINT 2 /* interrupt */
|
||||
#define SIGQUIT 3 /* quit */
|
||||
#define SIGILL 4 /* illegal instruction (not reset when caught) */
|
||||
#define SIGTRAP 5 /* trace trap (not reset when caught) */
|
||||
#define SIGIOT 6 /* IOT instruction */
|
||||
#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */
|
||||
#define SIGEMT 7 /* EMT instruction */
|
||||
#define SIGFPE 8 /* floating point exception */
|
||||
#define SIGKILL 9 /* kill (cannot be caught or ignored) */
|
||||
#define SIGBUS 10 /* bus error */
|
||||
#define SIGSEGV 11 /* segmentation violation */
|
||||
#define SIGSYS 12 /* bad argument to system call */
|
||||
#define SIGPIPE 13 /* write on a pipe with no one to read it */
|
||||
#define SIGALRM 14 /* alarm clock */
|
||||
#define SIGTERM 15 /* software termination signal from kill */
|
||||
#define SIGURG 16 /* urgent condition on IO channel */
|
||||
#define SIGSTOP 17 /* sendable stop signal not from tty */
|
||||
#define SIGTSTP 18 /* stop signal from tty */
|
||||
#define SIGCONT 19 /* continue a stopped process */
|
||||
#define SIGCHLD 20 /* to parent on child stop or exit */
|
||||
#define SIGCLD 20 /* System V name for SIGCHLD */
|
||||
#define SIGTTIN 21 /* to readers pgrp upon background tty read */
|
||||
#define SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */
|
||||
#define SIGIO 23 /* input/output possible signal */
|
||||
#define SIGPOLL SIGIO /* System V name for SIGIO */
|
||||
#define SIGXCPU 24 /* exceeded CPU time limit */
|
||||
#define SIGXFSZ 25 /* exceeded file size limit */
|
||||
#define SIGVTALRM 26 /* virtual time alarm */
|
||||
#define SIGPROF 27 /* profiling time alarm */
|
||||
#define SIGWINCH 28 /* window changed */
|
||||
#define SIGLOST 29 /* resource lost (eg, record-lock lost) */
|
||||
#define SIGUSR1 30 /* user defined signal 1 */
|
||||
#define SIGUSR2 31 /* user defined signal 2 */
|
||||
#define NSIG 32 /* signal 0 implied */
|
||||
|
||||
#ifndef _SIGNAL_H_
|
||||
/* Some applications take advantage of the fact that <sys/signal.h>
|
||||
* and <signal.h> are equivalent in glibc. Allow for that here. */
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __SYS_STATFS_H__
|
||||
#define __SYS_STATFS_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct statfs
|
||||
{
|
||||
size_t f_bsize; /* block size */
|
||||
size_t f_blocks; /* total data blocks in file system */
|
||||
size_t f_bfree; /* free blocks in file system */
|
||||
};
|
||||
|
||||
int statfs(const char *path, struct statfs *buf);
|
||||
int fstatfs(int fd, struct statfs *buf);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-09-07 Meco Man combine gcc armcc iccarm
|
||||
* 2021-02-12 Meco Man move all definitions located in <clock_time.h> to this file
|
||||
*/
|
||||
|
||||
#ifndef __SYS_TIME_H__
|
||||
#define __SYS_TIME_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h> /* for struct timeval */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* timezone */
|
||||
#define DST_NONE 0 /* not on dst */
|
||||
#define DST_USA 1 /* USA style dst */
|
||||
#define DST_AUST 2 /* Australian style dst */
|
||||
#define DST_WET 3 /* Western European dst */
|
||||
#define DST_MET 4 /* Middle European dst */
|
||||
#define DST_EET 5 /* Eastern European dst */
|
||||
#define DST_CAN 6 /* Canada */
|
||||
#define DST_GB 7 /* Great Britain and Eire */
|
||||
#define DST_RUM 8 /* Rumania */
|
||||
#define DST_TUR 9 /* Turkey */
|
||||
#define DST_AUSTALT 10 /* Australian style with shift in 1986 */
|
||||
|
||||
struct timezone
|
||||
{
|
||||
int tz_minuteswest; /* minutes west of Greenwich */
|
||||
int tz_dsttime; /* type of dst correction */
|
||||
};
|
||||
|
||||
#if !defined(_TIMEVAL_DEFINED) && !defined(_WIN32)
|
||||
#define _TIMEVAL_DEFINED
|
||||
struct timeval
|
||||
{
|
||||
time_t tv_sec; /* seconds */
|
||||
suseconds_t tv_usec; /* and microseconds */
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !(defined(__GNUC__) && !defined(__ARMCC_VERSION)/*GCC*/) && \
|
||||
!(defined(__ICCARM__) && (__VER__ >= 8010001)) && \
|
||||
!defined(_WIN32)
|
||||
struct timespec
|
||||
{
|
||||
time_t tv_sec; /* seconds */
|
||||
long tv_nsec; /* and nanoseconds */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure defined by POSIX.1b to be like a itimerval, but with
|
||||
* timespecs. Used in the timer_*() system calls.
|
||||
*/
|
||||
struct itimerspec
|
||||
{
|
||||
struct timespec it_interval;
|
||||
struct timespec it_value;
|
||||
};
|
||||
#endif
|
||||
|
||||
int stime(const time_t *t);
|
||||
time_t timegm(struct tm * const t);
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
int settimeofday(const struct timeval *tv, const struct timezone *tz);
|
||||
#if defined(__ARMCC_VERSION) || defined (__ICCARM__)
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *r);
|
||||
struct tm* localtime_r(const time_t* t, struct tm* r);
|
||||
char* asctime_r(const struct tm *t, char *buf);
|
||||
char *ctime_r(const time_t * tim_p, char * result);
|
||||
#elif defined(_WIN32)
|
||||
struct tm* gmtime_r(const time_t* timep, struct tm* r);
|
||||
struct tm* gmtime(const time_t* t);
|
||||
struct tm* localtime_r(const time_t* t, struct tm* r);
|
||||
struct tm* localtime(const time_t* t);
|
||||
time_t mktime(struct tm* const t);
|
||||
char* asctime_r(const struct tm* t, char* buf);
|
||||
char* ctime_r(const time_t* tim_p, char* result);
|
||||
char* ctime(const time_t* tim_p);
|
||||
time_t time(time_t* t);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_POSIX_DELAY
|
||||
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
|
||||
#endif /* RT_USING_POSIX_DELAY */
|
||||
|
||||
#if defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER)
|
||||
/* POSIX clock and timer */
|
||||
#define MILLISECOND_PER_SECOND 1000UL
|
||||
#define MICROSECOND_PER_SECOND 1000000UL
|
||||
#define NANOSECOND_PER_SECOND 1000000000UL
|
||||
|
||||
#define MILLISECOND_PER_TICK (MILLISECOND_PER_SECOND / RT_TICK_PER_SECOND)
|
||||
#define MICROSECOND_PER_TICK (MICROSECOND_PER_SECOND / RT_TICK_PER_SECOND)
|
||||
#define NANOSECOND_PER_TICK (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND)
|
||||
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 1
|
||||
#endif
|
||||
|
||||
#define CLOCK_CPUTIME_ID 2
|
||||
|
||||
#ifndef CLOCK_PROCESS_CPUTIME_ID
|
||||
#define CLOCK_PROCESS_CPUTIME_ID CLOCK_CPUTIME_ID
|
||||
#endif
|
||||
#ifndef CLOCK_THREAD_CPUTIME_ID
|
||||
#define CLOCK_THREAD_CPUTIME_ID CLOCK_CPUTIME_ID
|
||||
#endif
|
||||
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC 4
|
||||
#endif
|
||||
#endif /* defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER) */
|
||||
|
||||
#ifdef RT_USING_POSIX_CLOCK
|
||||
int clock_getres (clockid_t clockid, struct timespec *res);
|
||||
int clock_gettime (clockid_t clockid, struct timespec *tp);
|
||||
int clock_settime (clockid_t clockid, const struct timespec *tp);
|
||||
int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp);
|
||||
int rt_timespec_to_tick(const struct timespec *time);
|
||||
#endif /* RT_USING_POSIX_CLOCK */
|
||||
|
||||
#ifdef RT_USING_POSIX_TIMER
|
||||
#include "signal.h"
|
||||
int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid);
|
||||
int timer_delete(timer_t timerid);
|
||||
int timer_getoverrun(timer_t timerid);
|
||||
int timer_gettime(timer_t timerid, struct itimerspec *its);
|
||||
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
|
||||
struct itimerspec *ovalue);
|
||||
#endif /* RT_USING_POSIX_TIMER */
|
||||
|
||||
/* timezone */
|
||||
void tz_set(int8_t tz);
|
||||
int8_t tz_get(void);
|
||||
int8_t tz_is_dst(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_TIME_H_ */
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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 __SYS_VFS_H__
|
||||
#define __SYS_VFS_H__
|
||||
|
||||
#include "statfs.h" /* <sys/statfs.h> */
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,3 @@
|
||||
# DLIB (IAR) porting for RT-Thread
|
||||
|
||||
http://www.iarsys.co.jp/download/LMS2/arm/7502/ewarm7502doc/arm/doc/EWARM_DevelopmentGuide.ENU.pdf P.130
|
||||
@@ -0,0 +1,20 @@
|
||||
from building import *
|
||||
Import('rtconfig')
|
||||
|
||||
src = Glob('*.c')
|
||||
group = []
|
||||
|
||||
CPPDEFINES = ['RT_USING_DLIBC']
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
if GetDepend('DFS_USING_POSIX'):
|
||||
from distutils.version import LooseVersion
|
||||
from iar import IARVersion
|
||||
|
||||
CPPDEFINES = CPPDEFINES + ['_DLIB_FILE_DESCRIPTOR']
|
||||
if LooseVersion(IARVersion()) < LooseVersion("8.20.1"):
|
||||
CPPDEFINES = CPPDEFINES + ['_DLIB_THREAD_SUPPORT']
|
||||
|
||||
group = DefineGroup('Compiler', src, depend = [''], CPPDEFINES = CPPDEFINES)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-01-28 Bernard first version
|
||||
*/
|
||||
|
||||
const char *__environ = "OS=RT-Thread";
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-01-28 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <LowLevelIOInterface.h>
|
||||
#include <unistd.h>
|
||||
#include <compiler_private.h>
|
||||
#define DBG_TAG "dlib.syscall.close"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
/*
|
||||
* The "__close" function should close the file corresponding to
|
||||
* "handle". It should return 0 on success and nonzero on failure.
|
||||
*/
|
||||
|
||||
#pragma module_name = "?__close"
|
||||
|
||||
int __close(int handle)
|
||||
{
|
||||
if (handle == _LLIO_STDOUT ||
|
||||
handle == _LLIO_STDERR ||
|
||||
handle == _LLIO_STDIN)
|
||||
return _LLIO_ERROR;
|
||||
#ifdef DFS_USING_POSIX
|
||||
return close(handle);
|
||||
#else
|
||||
LOG_W(_WARNING_WITHOUT_FS);
|
||||
return _LLIO_ERROR;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-01-28 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <LowLevelIOInterface.h>
|
||||
#include <unistd.h>
|
||||
#include <compiler_private.h>
|
||||
#define DBG_TAG "dlib.syscall.lseek"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
/*
|
||||
* The "__lseek" function makes the next file operation (__read or
|
||||
* __write) act on a new location. The parameter "whence" specifies
|
||||
* how the "offset" parameter should be interpreted according to the
|
||||
* following table:
|
||||
*
|
||||
* 0 (=SEEK_SET) - Goto location "offset".
|
||||
* 1 (=SEEK_CUR) - Go "offset" bytes from the current location.
|
||||
* 2 (=SEEK_END) - Go to "offset" bytes from the end.
|
||||
*
|
||||
* This function should return the current file position, or -1 on
|
||||
* failure.
|
||||
*/
|
||||
|
||||
#pragma module_name = "?__lseek"
|
||||
|
||||
long __lseek(int handle, long offset, int whence)
|
||||
{
|
||||
if (handle == _LLIO_STDOUT ||
|
||||
handle == _LLIO_STDERR ||
|
||||
handle == _LLIO_STDIN)
|
||||
return _LLIO_ERROR;
|
||||
#ifdef DFS_USING_POSIX
|
||||
return lseek(handle, offset, whence);
|
||||
#else
|
||||
LOG_W(_WARNING_WITHOUT_FS);
|
||||
return _LLIO_ERROR;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-01-28 Bernard first version
|
||||
* 2021-11-13 Meco Man implement no-heap warning
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef RT_USING_HEAP
|
||||
#define DBG_TAG "dlib.syscall.mem"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
#define _NO_HEAP_ERROR() do{LOG_E("Please enable RT_USING_HEAP");\
|
||||
RT_ASSERT(0);\
|
||||
}while(0)
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
void *malloc(size_t n)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
return rt_malloc(n);
|
||||
#else
|
||||
_NO_HEAP_ERROR();
|
||||
return RT_NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *realloc(void *rmem, size_t newsize)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
return rt_realloc(rmem, newsize);
|
||||
#else
|
||||
_NO_HEAP_ERROR();
|
||||
return RT_NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *calloc(size_t nelem, size_t elsize)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
return rt_calloc(nelem, elsize);
|
||||
#else
|
||||
_NO_HEAP_ERROR();
|
||||
return RT_NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void free(void *rmem)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_free(rmem);
|
||||
#else
|
||||
_NO_HEAP_ERROR();
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-01-28 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <LowLevelIOInterface.h>
|
||||
#include <fcntl.h>
|
||||
#include <compiler_private.h>
|
||||
#define DBG_TAG "dlib.syscall.open"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
/*
|
||||
* The "__open" function opens the file named "filename" as specified
|
||||
* by "mode".
|
||||
*/
|
||||
|
||||
#pragma module_name = "?__open"
|
||||
|
||||
int __open(const char *filename, int mode)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int handle;
|
||||
int open_mode = O_RDONLY;
|
||||
|
||||
if (mode & _LLIO_CREAT)
|
||||
{
|
||||
open_mode |= O_CREAT;
|
||||
|
||||
/* Check what we should do with it if it exists. */
|
||||
if (mode & _LLIO_APPEND)
|
||||
{
|
||||
/* Append to the existing file. */
|
||||
open_mode |= O_APPEND;
|
||||
}
|
||||
|
||||
if (mode & _LLIO_TRUNC)
|
||||
{
|
||||
/* Truncate the existsing file. */
|
||||
open_mode |= O_TRUNC;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & _LLIO_TEXT)
|
||||
{
|
||||
/* we didn't support text mode */
|
||||
}
|
||||
|
||||
switch (mode & _LLIO_RDWRMASK)
|
||||
{
|
||||
case _LLIO_RDONLY:
|
||||
break;
|
||||
|
||||
case _LLIO_WRONLY:
|
||||
open_mode |= O_WRONLY;
|
||||
break;
|
||||
|
||||
case _LLIO_RDWR:
|
||||
/* The file should be opened for both reads and writes. */
|
||||
open_mode |= O_RDWR;
|
||||
break;
|
||||
|
||||
default:
|
||||
return _LLIO_ERROR;
|
||||
}
|
||||
|
||||
handle = open(filename, open_mode, 0);
|
||||
if (handle < 0)
|
||||
{
|
||||
return _LLIO_ERROR;
|
||||
}
|
||||
return handle;
|
||||
#else
|
||||
LOG_W(_WARNING_WITHOUT_FS);
|
||||
return _LLIO_ERROR;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-01-28 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <LowLevelIOInterface.h>
|
||||
#include <unistd.h>
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
#include "libc.h"
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
#include <compiler_private.h>
|
||||
#define DBG_TAG "dlib.syscall.read"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
/*
|
||||
* The "__read" function reads a number of bytes, at most "size" into
|
||||
* the memory area pointed to by "buffer". It returns the number of
|
||||
* bytes read, 0 at the end of the file, or _LLIO_ERROR if failure
|
||||
* occurs.
|
||||
*
|
||||
* The template implementation below assumes that the application
|
||||
* provides the function "MyLowLevelGetchar". It should return a
|
||||
* character value, or -1 on failure.
|
||||
*/
|
||||
|
||||
#pragma module_name = "?__read"
|
||||
|
||||
size_t __read(int handle, unsigned char *buf, size_t len)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int size;
|
||||
|
||||
if (handle == _LLIO_STDIN)
|
||||
{
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
if (libc_stdio_get_console() < 0)
|
||||
{
|
||||
LOG_W("Do not invoke standard input before initializing Compiler");
|
||||
return 0; /* error, but keep going */
|
||||
}
|
||||
return read(STDIN_FILENO, buf, len); /* return the length of the data read */
|
||||
#else
|
||||
LOG_W(_WARNING_WITHOUT_STDIO);
|
||||
return _LLIO_ERROR;
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
}
|
||||
else if ((handle == _LLIO_STDOUT) || (handle == _LLIO_STDERR))
|
||||
{
|
||||
return _LLIO_ERROR;
|
||||
}
|
||||
|
||||
size = read(handle, buf, len);
|
||||
return size; /* return the length of the data read */
|
||||
#else
|
||||
LOG_W(_WARNING_WITHOUT_FS);
|
||||
return _LLIO_ERROR;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-01-28 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <LowLevelIOInterface.h>
|
||||
#include <unistd.h>
|
||||
#include <compiler_private.h>
|
||||
#define DBG_TAG "dlib.syscall.remove"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
/*
|
||||
* The "remove" function should remove the file named "filename". It
|
||||
* should return 0 on success and nonzero on failure.
|
||||
*/
|
||||
|
||||
#pragma module_name = "?remove"
|
||||
|
||||
int remove(const char *filename)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
return unlink(filename);
|
||||
#else
|
||||
LOG_W(_WARNING_WITHOUT_FS);
|
||||
return _LLIO_ERROR;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-01-28 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <LowLevelIOInterface.h>
|
||||
#include <unistd.h>
|
||||
#include <compiler_private.h>
|
||||
#define DBG_TAG "dlib.syscall.write"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
/*
|
||||
* The "__write" function should output "size" number of bytes from
|
||||
* "buffer" in some application-specific way. It should return the
|
||||
* number of characters written, or _LLIO_ERROR on failure.
|
||||
*
|
||||
* If "buffer" is zero then __write should perform flushing of
|
||||
* internal buffers, if any. In this case "handle" can be -1 to
|
||||
* indicate that all handles should be flushed.
|
||||
*
|
||||
* The template implementation below assumes that the application
|
||||
* provides the function "MyLowLevelPutchar". It should return the
|
||||
* character written, or -1 on failure.
|
||||
*/
|
||||
|
||||
#pragma module_name = "?__write"
|
||||
|
||||
size_t __write(int handle, const unsigned char *buf, size_t len)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int size;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
|
||||
if ((handle == _LLIO_STDOUT) || (handle == _LLIO_STDERR))
|
||||
{
|
||||
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
|
||||
rt_device_t console_device;
|
||||
|
||||
console_device = rt_console_get_device();
|
||||
if (console_device)
|
||||
{
|
||||
rt_device_write(console_device, 0, buf, len);
|
||||
}
|
||||
|
||||
return len; /* return the length of the data written */
|
||||
#else
|
||||
return _LLIO_ERROR;
|
||||
#endif /* defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE) */
|
||||
}
|
||||
else if (handle == _LLIO_STDIN)
|
||||
{
|
||||
return _LLIO_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
size = write(handle, buf, len);
|
||||
return size; /* return the length of the data written */
|
||||
#else
|
||||
LOG_W(_WARNING_WITHOUT_FS);
|
||||
return _LLIO_ERROR;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-02-13 Meco Man implement exit() and abort()
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/* for exit() and abort() */
|
||||
void __exit (int status)
|
||||
{
|
||||
extern void __rt_libc_exit(int status);
|
||||
__rt_libc_exit(status);
|
||||
while(1);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# NEWLIB (GCC) porting for RT-Thread
|
||||
|
||||
https://sourceware.org/newlib/libc.html#Reentrancy
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
from building import *
|
||||
from gcc import *
|
||||
Import('rtconfig')
|
||||
|
||||
src = []
|
||||
cwd = GetCurrentDir()
|
||||
group = []
|
||||
LIBS = ['m'] # link libm
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
LIBS += ['c'] # link libc
|
||||
src += Glob('*.c')
|
||||
|
||||
#report newlib version
|
||||
print('Newlib version:' + GetNewLibVersion(rtconfig))
|
||||
|
||||
# identify this is Newlib, and only enable POSIX.1-1990
|
||||
CPPDEFINES = ['RT_USING_NEWLIB', '_POSIX_C_SOURCE=1']
|
||||
|
||||
group = DefineGroup('Compiler', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES, LIBS = LIBS)
|
||||
|
||||
|
||||
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')
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-02 Meco Man First version
|
||||
*/
|
||||
|
||||
#ifndef __FCNTL_H__
|
||||
#define __FCNTL_H__
|
||||
|
||||
#include <sys/_default_fcntl.h>
|
||||
|
||||
#ifndef O_DIRECTORY
|
||||
#define O_DIRECTORY 0x200000
|
||||
#endif
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0x10000
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -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')
|
||||
@@ -0,0 +1,20 @@
|
||||
from shutil import copy
|
||||
from building import *
|
||||
from gcc import *
|
||||
Import('rtconfig')
|
||||
|
||||
src = []
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd]
|
||||
group = []
|
||||
|
||||
# sys/select.h does not exist in newlib 2.2.0 or lower version
|
||||
if rtconfig.PLATFORM == 'gcc' and (CheckHeader(rtconfig, 'sys/select.h') == False):
|
||||
try:
|
||||
copy("../../../../common/nogcc/sys/select.h", "./sys/select.h") # copy from 'nogcc/sys/select.h'
|
||||
except:
|
||||
pass
|
||||
|
||||
group = DefineGroup('Compiler', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,2 @@
|
||||
Newlib 2.2.0 or lower version does not provide `sys/select.h`, and `fd_set` is defined in `sys/types.h`. It will be generated by scons automatically, and **DO NOT** change it.
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-07-21 Meco Man The first version
|
||||
*/
|
||||
|
||||
#ifndef __SYS_SELECT_H__
|
||||
#define __SYS_SELECT_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#ifndef FD_SETSIZE
|
||||
#define FD_SETSIZE 32
|
||||
#endif
|
||||
|
||||
#ifdef SAL_USING_POSIX
|
||||
#ifdef FD_SETSIZE
|
||||
#undef FD_SETSIZE
|
||||
#endif
|
||||
#define FD_SETSIZE DFS_FD_MAX
|
||||
#endif /* SAL_USING_POSIX */
|
||||
|
||||
typedef long fd_mask;
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef _SYS_TYPES_FD_SET /* MIPS */
|
||||
|
||||
#define NBBY 8 /* number of bits in a byte */
|
||||
#define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */
|
||||
#ifndef howmany
|
||||
#define howmany(x,y) (((x)+((y)-1))/(y))
|
||||
#endif
|
||||
|
||||
typedef struct _types_fd_set {
|
||||
fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
|
||||
} _types_fd_set;
|
||||
#define fd_set _types_fd_set
|
||||
|
||||
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS)))
|
||||
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS)))
|
||||
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS)))
|
||||
#define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p)))
|
||||
#endif /* _SYS_TYPES_FD_SET */
|
||||
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* __SYS_SELECT_H__ */
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-02-16 Meco Man The first version
|
||||
*/
|
||||
|
||||
#ifndef _MACHTIME_H_
|
||||
#define _MACHTIME_H_
|
||||
|
||||
#include <rtconfig.h>
|
||||
#define _CLOCKS_PER_SEC_ RT_TICK_PER_SECOND
|
||||
|
||||
#endif /* _MACHTIME_H_ */
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-02-11 Meco Man remove _gettimeofday_r() and _times_r()
|
||||
* 2020-02-13 Meco Man re-implement exit() and abort()
|
||||
* 2020-02-21 Meco Man improve and beautify syscalls
|
||||
* 2020-02-24 Meco Man fix bug of _isatty_r()
|
||||
*/
|
||||
|
||||
#include <reent.h>
|
||||
#include <rtthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
#include "libc.h"
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
#ifdef RT_USING_MODULE
|
||||
#include <dlmodule.h>
|
||||
#endif /* RT_USING_MODULE */
|
||||
#include <compiler_private.h>
|
||||
#define DBG_TAG "newlib.syscalls"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef RT_USING_HEAP /* Memory routine */
|
||||
void *_malloc_r (struct _reent *ptr, size_t size)
|
||||
{
|
||||
void* result;
|
||||
|
||||
result = (void*)rt_malloc (size);
|
||||
if (result == RT_NULL)
|
||||
{
|
||||
ptr->_errno = ENOMEM;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *_realloc_r (struct _reent *ptr, void *old, size_t newlen)
|
||||
{
|
||||
void* result;
|
||||
|
||||
result = (void*)rt_realloc (old, newlen);
|
||||
if (result == RT_NULL)
|
||||
{
|
||||
ptr->_errno = ENOMEM;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *_calloc_r (struct _reent *ptr, size_t size, size_t len)
|
||||
{
|
||||
void* result;
|
||||
|
||||
result = (void*)rt_calloc (size, len);
|
||||
if (result == RT_NULL)
|
||||
{
|
||||
ptr->_errno = ENOMEM;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void _free_r (struct _reent *ptr, void *addr)
|
||||
{
|
||||
rt_free (addr);
|
||||
}
|
||||
|
||||
#else
|
||||
void *
|
||||
_sbrk_r(struct _reent *ptr, ptrdiff_t incr)
|
||||
{
|
||||
LOG_E("Please enable RT_USING_HEAP");
|
||||
RT_ASSERT(0);
|
||||
return RT_NULL;
|
||||
}
|
||||
#endif /*RT_USING_HEAP*/
|
||||
|
||||
void __libc_init_array(void)
|
||||
{
|
||||
/* we not use __libc init_aray to initialize C++ objects */
|
||||
/* __libc_init_array is ARM code, not Thumb; it will cause a hardfault. */
|
||||
}
|
||||
|
||||
/* Reentrant versions of system calls. */
|
||||
#ifndef _REENT_ONLY
|
||||
int *__errno ()
|
||||
{
|
||||
return _rt_errno();
|
||||
}
|
||||
#endif
|
||||
|
||||
int _getpid_r(struct _reent *ptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _close_r(struct _reent *ptr, int fd)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
return close(fd);
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
int _execve_r(struct _reent *ptr, const char * name, char *const *argv, char *const *env)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _fcntl_r(struct _reent *ptr, int fd, int cmd, int arg)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _fork_r(struct _reent *ptr)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _fstat_r(struct _reent *ptr, int fd, struct stat *pstat)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _isatty_r(struct _reent *ptr, int fd)
|
||||
{
|
||||
if (fd >=0 && fd < 3)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int _kill_r(struct _reent *ptr, int pid, int sig)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _link_r(struct _reent *ptr, const char *old, const char *new)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _wait_r(struct _reent *ptr, int *status)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mode_t umask(mode_t mask)
|
||||
{
|
||||
return 022;
|
||||
}
|
||||
|
||||
int flock(int fd, int operation)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
_off_t _lseek_r(struct _reent *ptr, int fd, _off_t pos, int whence)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
_off_t rc;
|
||||
rc = lseek(fd, pos, whence);
|
||||
return rc;
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
int _mkdir_r(struct _reent *ptr, const char *name, int mode)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int rc;
|
||||
rc = mkdir(name, mode);
|
||||
return rc;
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
int _open_r(struct _reent *ptr, const char *file, int flags, int mode)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int rc;
|
||||
rc = open(file, flags, mode);
|
||||
return rc;
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
_ssize_t _read_r(struct _reent *ptr, int fd, void *buf, size_t nbytes)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
_ssize_t rc;
|
||||
if (fd == STDIN_FILENO)
|
||||
{
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
if (libc_stdio_get_console() < 0)
|
||||
{
|
||||
LOG_W("Do not invoke standard input before initializing Compiler");
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_STDIO);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* RT_USING_POSIX_STDIO */
|
||||
}
|
||||
else if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = read(fd, buf, nbytes);
|
||||
return rc;
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
int _rename_r(struct _reent *ptr, const char *old, const char *new)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int rc;
|
||||
rc = rename(old, new);
|
||||
return rc;
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
int _stat_r(struct _reent *ptr, const char *file, struct stat *pstat)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
int rc;
|
||||
rc = stat(file, pstat);
|
||||
return rc;
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
int _unlink_r(struct _reent *ptr, const char *file)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
return unlink(file);
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
_ssize_t _write_r(struct _reent *ptr, int fd, const void *buf, size_t nbytes)
|
||||
{
|
||||
#ifdef DFS_USING_POSIX
|
||||
_ssize_t rc;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
|
||||
if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
|
||||
{
|
||||
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
|
||||
rt_device_t console;
|
||||
|
||||
console = rt_console_get_device();
|
||||
if (console)
|
||||
return rt_device_write(console, -1, buf, nbytes);
|
||||
#else
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE) */
|
||||
}
|
||||
else if (fd == STDIN_FILENO)
|
||||
{
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DFS_USING_POSIX
|
||||
rc = write(fd, buf, nbytes);
|
||||
return rc;
|
||||
#else
|
||||
LOG_W("%s: %s", __func__, _WARNING_WITHOUT_FS);
|
||||
ptr->_errno = ENOTSUP;
|
||||
return -1;
|
||||
#endif /* DFS_USING_POSIX */
|
||||
}
|
||||
|
||||
/* for exit() and abort() */
|
||||
__attribute__ ((noreturn)) void _exit (int status)
|
||||
{
|
||||
extern void __rt_libc_exit(int status);
|
||||
__rt_libc_exit(status);
|
||||
while(1);
|
||||
}
|
||||
|
||||
/*
|
||||
These functions are implemented and replaced by the 'common/time.c' file
|
||||
int _gettimeofday_r(struct _reent *ptr, struct timeval *__tp, void *__tzp);
|
||||
_CLOCK_T_ _times_r(struct _reent *ptr, struct tms *ptms);
|
||||
*/
|
||||
@@ -0,0 +1 @@
|
||||
This folder provides uniformed header files crossing different compiler platforms, and supports basic standard C library functions, such as memory management and time management, etc.
|
||||
@@ -0,0 +1,15 @@
|
||||
menuconfig RT_USING_CPLUSPLUS
|
||||
bool "Enable C++ features"
|
||||
default n
|
||||
|
||||
if RT_USING_CPLUSPLUS
|
||||
|
||||
config RT_USING_CPLUSPLUS11
|
||||
bool "Enable c++11 threading feature support"
|
||||
default n
|
||||
select RT_USING_POSIX_FS
|
||||
select RT_USING_POSIX_STDIO
|
||||
select RT_USING_PTHREADS
|
||||
select RT_USING_RTC
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,52 @@
|
||||
# C++ support for RT-Thread #
|
||||
|
||||
This is the C++ component in RT-Thread RTOS. In order to support C++ language, this component
|
||||
implement a basic environment, such as new/delete operators.
|
||||
|
||||
Because RT-Thread RTOS is used in embedded system mostly, there are some rules for C++ applications:
|
||||
|
||||
1. DOES NOT use exception.
|
||||
2. DOES NOT use Run-Time Type Information (RTTI).
|
||||
3. Template is discouraged and it easily causes code text large.
|
||||
4. Static class variables are discouraged. The time and place to call their constructor function could not be precisely controlled and make multi-threaded programming a nightmare.
|
||||
5. Multiple inheritance is strongly discouraged, as it can cause intolerable confusion.
|
||||
|
||||
About GNU GCC compiler
|
||||
|
||||
please add following string in your ld link script:
|
||||
|
||||
// in your .text section
|
||||
PROVIDE(__ctors_start__ = .);
|
||||
/* old GCC version uses .ctors */
|
||||
KEEP(*(SORT(.ctors.*)))
|
||||
KEEP(*(.ctors))
|
||||
/* new GCC version uses .init_array */
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE(__ctors_end__ = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
|
||||
// as a standalone section if you use ARM target.
|
||||
|
||||
/* The .ARM.exidx section is used for C++ exception handling. */
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
__exidx_start = .;
|
||||
ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
|
||||
/* This is used by the startup in order to initialize the .data secion */
|
||||
_sidata = .;
|
||||
} > CODE
|
||||
__exidx_end = .;
|
||||
|
||||
/* .data section which is used for initialized data */
|
||||
|
||||
// in your .data section
|
||||
PROVIDE(__dtors_start__ = .);
|
||||
KEEP(*(SORT(.dtors.*)))
|
||||
KEEP(*(.dtors))
|
||||
PROVIDE(__dtors_end__ = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.cpp') + Glob('*.c')
|
||||
|
||||
if GetDepend('RT_USING_CPLUSPLUS11'):
|
||||
src += Glob('cpp11/*.cpp') + Glob('cpp11/*.c')
|
||||
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armclang' and GetDepend('RT_USING_CPLUSPLUS11'):
|
||||
src += Glob('cpp11/armclang/*.cpp') + Glob('cpp11/armclang/*.c')
|
||||
CPPPATH += [cwd + '/cpp11/armclang']
|
||||
elif rtconfig.PLATFORM == 'gcc' and GetDepend('RT_USING_CPLUSPLUS11'):
|
||||
src += Glob('cpp11/gcc/*.cpp') + Glob('cpp11/gcc/*.c')
|
||||
CPPPATH += [cwd + '/cpp11/gcc']
|
||||
|
||||
group = DefineGroup('CPlusPlus', src, depend = ['RT_USING_CPLUSPLUS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,49 @@
|
||||
# C++ 11 support for RT-Thread
|
||||
|
||||
## Features
|
||||
|
||||
Here are some features about rt-thread c++11 threading futures.
|
||||
|
||||
- Atomic.
|
||||
- Conditional variables.
|
||||
- Clocks.
|
||||
- Future.
|
||||
- Mutexes.
|
||||
- Threads.
|
||||
- TLS.
|
||||
|
||||
## How To Use
|
||||
|
||||
Note that using C++ 11 in rt-thread requires modifying some of the files in the toolchain. Before modifying the tool, back up the tool chain.
|
||||
|
||||
1. Enable c++11 support
|
||||
|
||||

|
||||
|
||||
2. Download toolchain GCC 10.2.1:
|
||||
|
||||
```shell
|
||||
gcc version 10.2.1 20201103 (release) (GNU Arm Embedded Toolchain 10-2020-q4-major)
|
||||
```
|
||||
|
||||
3. Delete the following files:
|
||||
|
||||
```shell
|
||||
rm -f toolchain/arm-none-eabi/include/c++/10.2.1/thread
|
||||
rm -f toolchain/arm-none-eabi/include/c++/10.2.1/mutex
|
||||
rm -f toolchain/arm-none-eabi/include/c++/10.2.1/condition_variable
|
||||
rm -f toolchain/arm-none-eabi/include/c++/10.2.1/future
|
||||
rm -f toolchain/arm-none-eabi/include/pthread.h
|
||||
```
|
||||
|
||||
4. Clear the contents of the following files and keep them to prevent compilation failures:
|
||||
|
||||
```shell
|
||||
toolchain/arm-none-eabi/include/sys/_pthreadtypes.h
|
||||
```
|
||||
|
||||
5. Update `rtconfig.py` file. add compilation parameters:
|
||||
|
||||
```shell
|
||||
CXXFLAGS = CFLAGS + ' -std=c++11 -fabi-version=0 -MMD -MP -MF'
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
# cpp 11 support for rt-thread
|
||||
|
||||
## 特性
|
||||
|
||||
下面是 RT-Thread 支持的 C++ 11 线程特性。
|
||||
|
||||
- Atomic.
|
||||
- Conditional variables.
|
||||
- Clocks.
|
||||
- Future.
|
||||
- Mutexes.
|
||||
- Threads.
|
||||
- TLS.
|
||||
|
||||
## 如何使用
|
||||
|
||||
请注意,在 RT-Thread 中使用 C++ 11,需要修改工具链中的部分文件。请在修改之前,备份好工具链。
|
||||
|
||||
1. 使能 c++11
|
||||

|
||||
|
||||
2. 下载 GCC 工具链
|
||||
|
||||
```shell
|
||||
gcc version 10.2.1 20201103 (release) (GNU Arm Embedded Toolchain 10-2020-q4-major)
|
||||
```
|
||||
|
||||
3. 删除下面的文件
|
||||
|
||||
```shell
|
||||
rm -f toolchain/arm-none-eabi/include/c++/10.2.1/thread
|
||||
rm -f toolchain/arm-none-eabi/include/c++/10.2.1/mutex
|
||||
rm -f toolchain/arm-none-eabi/include/c++/10.2.1/condition_variable
|
||||
rm -f toolchain/arm-none-eabi/include/c++/10.2.1/future
|
||||
rm -f toolchain/arm-none-eabi/include/pthread.h
|
||||
```
|
||||
|
||||
4. 请清除下面文件的内容,保留文件避免编译失败
|
||||
|
||||
```shell
|
||||
toolchain/arm-none-eabi/include/sys/_pthreadtypes.h
|
||||
```
|
||||
|
||||
5. 更新 `rtconfig.py` 文件,添加 c++ 编译参数:
|
||||
|
||||
```shell
|
||||
CXXFLAGS = CFLAGS + ' -std=c++11 -fabi-version=0 -MMD -MP -MF'
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include <arm-tpl.h>
|
||||
#include <sys/time.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
extern "C" int __ARM_TPL_clock_realtime(__ARM_TPL_timespec_t* __ts)
|
||||
{
|
||||
unsigned int t = std::time(nullptr);
|
||||
__ts->tv_sec = t;
|
||||
__ts->tv_nsec = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_clock_monotonic(__ARM_TPL_timespec_t* __ts)
|
||||
{
|
||||
unsigned int t = rt_tick_get();
|
||||
__ts->tv_sec = t / RT_TICK_PER_SECOND;
|
||||
__ts->tv_nsec = (t %RT_TICK_PER_SECOND) * NANOSECOND_PER_TICK ;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include <arm-tpl.h>
|
||||
#include "tpl.h"
|
||||
#include <new>
|
||||
#include <cstdint>
|
||||
#include <stdatomic.h>
|
||||
|
||||
arm_tpl_cv::arm_tpl_cv()
|
||||
{
|
||||
s = rt_sem_create("semxs", 0, RT_IPC_FLAG_PRIO);
|
||||
if (s == nullptr)
|
||||
RT_ASSERT(0);
|
||||
h = rt_sem_create("semxh", 0, RT_IPC_FLAG_PRIO);
|
||||
if (h == nullptr)
|
||||
{
|
||||
rt_sem_delete(s);
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
x = rt_mutex_create("mutx", RT_IPC_FLAG_PRIO);
|
||||
if (x == nullptr)
|
||||
{
|
||||
rt_sem_delete(s);
|
||||
rt_sem_delete(h);
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
arm_tpl_cv::~arm_tpl_cv()
|
||||
{
|
||||
rt_mutex_delete(x);
|
||||
rt_sem_delete(h);
|
||||
rt_sem_delete(s);
|
||||
}
|
||||
|
||||
void arm_tpl_cv::wait(rt_mutex_t lock, bool recursive)
|
||||
{
|
||||
while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
|
||||
rt_sem_release(s);
|
||||
rt_mutex_release(x);
|
||||
if (recursive)
|
||||
rt_mutex_release(lock);
|
||||
else
|
||||
rt_mutex_release(lock);
|
||||
while (rt_sem_take(h, ARM_TPL_MAX_DELAY) != 0);
|
||||
if (recursive)
|
||||
while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0);
|
||||
else
|
||||
while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0);
|
||||
}
|
||||
|
||||
int arm_tpl_cv::timedwait(rt_mutex_t lock, bool recursive, unsigned int timeout_ms)
|
||||
{
|
||||
int result = 0;
|
||||
while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
|
||||
rt_sem_release(s);
|
||||
rt_mutex_release(x);
|
||||
if (recursive)
|
||||
rt_mutex_release(lock);
|
||||
else
|
||||
rt_mutex_release(lock);
|
||||
if (rt_sem_take(h, rt_tick_from_millisecond(timeout_ms)) != 0)
|
||||
{
|
||||
while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
|
||||
if (rt_sem_take(h, 0) != 0)
|
||||
{
|
||||
if (rt_sem_take(s, 0) != 0)
|
||||
result = -1;
|
||||
else
|
||||
result = 1;
|
||||
}
|
||||
rt_mutex_release(x);
|
||||
}
|
||||
if (recursive)
|
||||
while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0);
|
||||
else
|
||||
while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
void arm_tpl_cv::signal()
|
||||
{
|
||||
while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
|
||||
if (rt_sem_take(s, 0) == 0)
|
||||
rt_sem_release(h);
|
||||
rt_mutex_release(x);
|
||||
}
|
||||
|
||||
void arm_tpl_cv::broadcast()
|
||||
{
|
||||
while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
|
||||
auto count = s->value;
|
||||
for (auto i = 0; i < count; i++)
|
||||
{
|
||||
while (rt_sem_take(s, ARM_TPL_MAX_DELAY) != 0);
|
||||
rt_sem_release(h);
|
||||
}
|
||||
rt_mutex_release(x);
|
||||
}
|
||||
|
||||
static int check_create(volatile __ARM_TPL_condvar_t *__vcv)
|
||||
{
|
||||
if (__vcv->data == 0)
|
||||
{
|
||||
uintptr_t cv_new;
|
||||
cv_new = reinterpret_cast<uintptr_t>(new arm_tpl_cv());
|
||||
if (cv_new == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
uintptr_t cv_null = 0;
|
||||
if (!atomic_compare_exchange_strong(&__vcv->data, &cv_null, cv_new))
|
||||
delete reinterpret_cast<arm_tpl_cv *>(cv_new);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_condvar_wait(__ARM_TPL_condvar_t *__cv, __ARM_TPL_mutex_t *__m)
|
||||
{
|
||||
volatile __ARM_TPL_condvar_t *__vcv = __cv;
|
||||
if (check_create(__vcv) != 0)
|
||||
return -1;
|
||||
struct arm_tpl_mutex_struct *tmutex = (struct arm_tpl_mutex_struct *)(__m->data);
|
||||
((arm_tpl_cv *) __vcv->data)->wait(tmutex->mutex, tmutex->type == RECURSIVE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_condvar_timedwait(__ARM_TPL_condvar_t *__cv,
|
||||
__ARM_TPL_mutex_t *__m,
|
||||
__ARM_TPL_timespec_t *__ts)
|
||||
{
|
||||
volatile __ARM_TPL_condvar_t *__vcv = __cv;
|
||||
if (check_create(__vcv) != 0)
|
||||
return -1;
|
||||
__ARM_TPL_timespec_t now;
|
||||
if (__ARM_TPL_clock_realtime(&now) != 0)
|
||||
return -1;
|
||||
struct arm_tpl_mutex_struct *tmutex = (struct arm_tpl_mutex_struct *)(__m->data);
|
||||
unsigned int timeout_ms = (__ts->tv_sec - now.tv_sec) * 1000 + (__ts->tv_nsec - now.tv_nsec) / 1000000;
|
||||
if (((arm_tpl_cv *) __vcv->data)->timedwait(tmutex->mutex, tmutex->type == RECURSIVE, timeout_ms) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_condvar_signal(__ARM_TPL_condvar_t *__cv)
|
||||
{
|
||||
volatile __ARM_TPL_condvar_t *__vcv = __cv;
|
||||
if (__vcv->data != 0)
|
||||
((arm_tpl_cv *) __vcv->data)->signal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_condvar_broadcast(__ARM_TPL_condvar_t *__cv)
|
||||
{
|
||||
volatile __ARM_TPL_condvar_t *__vcv = __cv;
|
||||
if (__vcv->data != 0)
|
||||
((arm_tpl_cv *) __vcv->data)->broadcast();
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_condvar_destroy(__ARM_TPL_condvar_t *__cv)
|
||||
{
|
||||
volatile __ARM_TPL_condvar_t *__vcv = __cv;
|
||||
if (__vcv->data != 0)
|
||||
{
|
||||
delete (arm_tpl_cv *) __vcv->data;
|
||||
__vcv->data = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include <arm-tpl.h>
|
||||
|
||||
extern "C" int __ARM_TPL_execute_once(__ARM_TPL_exec_once_flag *__flag,
|
||||
void (*__init_routine)(void))
|
||||
{
|
||||
if (*__flag == 0)
|
||||
{
|
||||
__init_routine();
|
||||
*__flag = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include <arm-tpl.h>
|
||||
#include <cstdint>
|
||||
#include <stdatomic.h>
|
||||
#include "tpl.h"
|
||||
|
||||
static int check_create(volatile __ARM_TPL_mutex_t *__vm, bool recursive = false)
|
||||
{
|
||||
if (__vm->data == 0)
|
||||
{
|
||||
uintptr_t mut_null = 0;
|
||||
arm_tpl_mutex_struct *mutex_p = (arm_tpl_mutex_struct *)rt_malloc(sizeof(arm_tpl_mutex_struct));
|
||||
if (mutex_p == nullptr) return -1;
|
||||
|
||||
if (recursive)
|
||||
mutex_p->mutex = rt_mutex_create("mutexx", RT_IPC_FLAG_PRIO);
|
||||
else
|
||||
mutex_p->mutex = rt_mutex_create("mutexx", RT_IPC_FLAG_PRIO);
|
||||
|
||||
if (mutex_p->mutex == nullptr)
|
||||
{
|
||||
rt_free(mutex_p);
|
||||
return -1;
|
||||
}
|
||||
mutex_p->type = recursive ? RECURSIVE : NORMAL;
|
||||
uintptr_t mut_new = reinterpret_cast<uintptr_t>(mutex_p);
|
||||
if (!atomic_compare_exchange_strong(&__vm->data, &mut_null, mut_new))
|
||||
{
|
||||
rt_mutex_delete(mutex_p->mutex);
|
||||
rt_free(mutex_p);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mutexLock(arm_tpl_mutex_struct *mutex_p, rt_tick_t timeOut)
|
||||
{
|
||||
if (mutex_p->type == RECURSIVE)
|
||||
{
|
||||
if (rt_mutex_take(mutex_p->mutex, timeOut) == 0)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rt_mutex_take(mutex_p->mutex, timeOut) == 0)
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mutexUnlock(arm_tpl_mutex_struct *mutex_p)
|
||||
{
|
||||
if (mutex_p->type == RECURSIVE)
|
||||
rt_mutex_release(mutex_p->mutex);
|
||||
else
|
||||
rt_mutex_release(mutex_p->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_recursive_mutex_init(__ARM_TPL_mutex_t *__m)
|
||||
{
|
||||
volatile __ARM_TPL_mutex_t *__vm = __m;
|
||||
return check_create(__vm, true);
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_mutex_lock(__ARM_TPL_mutex_t *__m)
|
||||
{
|
||||
volatile __ARM_TPL_mutex_t *__vm = __m;
|
||||
if (check_create(__vm))
|
||||
return -1;
|
||||
while (mutexLock((arm_tpl_mutex_struct *)(__vm->data), ARM_TPL_MAX_DELAY) != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_mutex_trylock(__ARM_TPL_mutex_t *__m)
|
||||
{
|
||||
volatile __ARM_TPL_mutex_t *__vm = __m;
|
||||
if (check_create(__vm))
|
||||
return -1;
|
||||
return mutexLock((arm_tpl_mutex_struct *)(__vm->data), 0);
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_mutex_unlock(__ARM_TPL_mutex_t *__m)
|
||||
{
|
||||
volatile __ARM_TPL_mutex_t *__vm = __m;
|
||||
return mutexUnlock((arm_tpl_mutex_struct *)(__vm->data));
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_mutex_destroy(__ARM_TPL_mutex_t *__m)
|
||||
{
|
||||
volatile __ARM_TPL_mutex_t *__vm = __m;
|
||||
if (__vm->data != 0)
|
||||
{
|
||||
rt_mutex_delete(((arm_tpl_mutex_struct *)(__vm->data))->mutex);
|
||||
rt_free((void *)(__vm->data));
|
||||
__vm->data = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include <arm-tpl.h>
|
||||
#include "tpl.h"
|
||||
#include <cstdio>
|
||||
#include <pthread.h>
|
||||
|
||||
#define CPP11_DEFAULT_ID_OFFSET 1
|
||||
|
||||
extern "C" int __ARM_TPL_thread_create(__ARM_TPL_thread_t *__t,
|
||||
void *(*__func)(void *),
|
||||
void *__arg)
|
||||
{
|
||||
int ret = 0;
|
||||
pthread_t pid;
|
||||
ret = pthread_create(&pid, RT_NULL, __func, __arg);
|
||||
if (ret == 0)
|
||||
{
|
||||
__t->data = (std::uintptr_t)pid + CPP11_DEFAULT_ID_OFFSET;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_thread_id_compare(__ARM_TPL_thread_id __tid1,
|
||||
__ARM_TPL_thread_id __tid2)
|
||||
{
|
||||
if (__tid1 > __tid2)
|
||||
return 1;
|
||||
else if (__tid1 < __tid2)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" __ARM_TPL_thread_id __ARM_TPL_thread_get_current_id()
|
||||
{
|
||||
return (__ARM_TPL_thread_id)pthread_self();
|
||||
}
|
||||
|
||||
extern "C" __ARM_TPL_thread_id __ARM_TPL_thread_get_id(
|
||||
const __ARM_TPL_thread_t *__t)
|
||||
{
|
||||
return (__ARM_TPL_thread_id)(((pthread_t)__t->data - CPP11_DEFAULT_ID_OFFSET));
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_thread_join(__ARM_TPL_thread_t *__t)
|
||||
{
|
||||
pthread_join(((pthread_t)__t->data - CPP11_DEFAULT_ID_OFFSET), RT_NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_thread_detach(__ARM_TPL_thread_t *__t)
|
||||
{
|
||||
pthread_detach(((pthread_t)__t->data - CPP11_DEFAULT_ID_OFFSET));
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void __ARM_TPL_thread_yield()
|
||||
{
|
||||
rt_thread_yield();
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_thread_nanosleep(const __ARM_TPL_timespec_t *__req,
|
||||
__ARM_TPL_timespec_t *__rem)
|
||||
{
|
||||
rt_tick_t tick;
|
||||
|
||||
tick = __req->tv_sec * RT_TICK_PER_SECOND + (__req->tv_nsec * RT_TICK_PER_SECOND)/ 1000000000;
|
||||
rt_thread_delay(tick);
|
||||
|
||||
if (__rem)
|
||||
{
|
||||
tick = rt_tick_get() - tick;
|
||||
/* get the passed time */
|
||||
__rem->tv_sec = tick/RT_TICK_PER_SECOND;
|
||||
__rem->tv_nsec = (tick%RT_TICK_PER_SECOND) * (1000000000/RT_TICK_PER_SECOND);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" unsigned __ARM_TPL_thread_hw_concurrency()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_tls_create(__ARM_TPL_tls_key *__key,
|
||||
void (*__at_exit)(void *))
|
||||
{
|
||||
pthread_key_t key;
|
||||
|
||||
if (pthread_key_create(&key, __at_exit) == 0)
|
||||
{
|
||||
*__key = key;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" void *__ARM_TPL_tls_get(__ARM_TPL_tls_key __key)
|
||||
{
|
||||
return pthread_getspecific(__key);
|
||||
}
|
||||
|
||||
extern "C" int __ARM_TPL_tls_set(__ARM_TPL_tls_key __key, void *__p)
|
||||
{
|
||||
if (pthread_setspecific(__key, (void*)__p) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __cplusplus
|
||||
void ARMTPLInit();
|
||||
#else
|
||||
#include <rtthread.h>
|
||||
|
||||
#define ARM_TPL_MAX_DELAY 1000
|
||||
#define ARM_TPL_THREAD_STACK_SIZE 4096
|
||||
|
||||
enum arm_tpl_mutex_type
|
||||
{
|
||||
NORMAL,
|
||||
RECURSIVE,
|
||||
};
|
||||
|
||||
struct arm_tpl_mutex_struct
|
||||
{
|
||||
rt_mutex_t mutex;
|
||||
arm_tpl_mutex_type type;
|
||||
};
|
||||
|
||||
struct arm_tpl_thread_struct
|
||||
{
|
||||
rt_thread_t task;
|
||||
void *(*func)(void *);
|
||||
void *arg;
|
||||
rt_sem_t join_sem;
|
||||
rt_sem_t detach_sem;
|
||||
};
|
||||
|
||||
class arm_tpl_cv
|
||||
{
|
||||
public:
|
||||
arm_tpl_cv();
|
||||
~arm_tpl_cv();
|
||||
void wait(rt_mutex_t lock, bool recursive);
|
||||
int timedwait(rt_mutex_t lock, bool recursive, unsigned int timeout_ms);
|
||||
void signal();
|
||||
void broadcast();
|
||||
private:
|
||||
rt_sem_t s;
|
||||
rt_sem_t h;
|
||||
rt_mutex_t x;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 peterfan Add copyright header.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
* override gcc builtin atomic function for std::atomic<int64_t>, std::atomic<uint64_t>
|
||||
* @see https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
|
||||
*/
|
||||
uint64_t __atomic_load_8(volatile void *ptr, int memorder)
|
||||
{
|
||||
volatile uint64_t *val_ptr = (volatile uint64_t *)ptr;
|
||||
register rt_base_t level;
|
||||
uint64_t tmp;
|
||||
level = rt_hw_interrupt_disable();
|
||||
tmp = *val_ptr;
|
||||
rt_hw_interrupt_enable(level);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void __atomic_store_8(volatile void *ptr, uint64_t val, int memorder)
|
||||
{
|
||||
volatile uint64_t *val_ptr = (volatile uint64_t *)ptr;
|
||||
register rt_base_t level;
|
||||
level = rt_hw_interrupt_disable();
|
||||
*val_ptr = val;
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
uint64_t __atomic_exchange_8(volatile void *ptr, uint64_t val, int memorder)
|
||||
{
|
||||
volatile uint64_t *val_ptr = (volatile uint64_t *)ptr;
|
||||
register rt_base_t level;
|
||||
uint64_t tmp;
|
||||
level = rt_hw_interrupt_disable();
|
||||
tmp = *val_ptr;
|
||||
*val_ptr = val;
|
||||
rt_hw_interrupt_enable(level);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool __atomic_compare_exchange_8(volatile void *ptr, volatile void *expected, uint64_t desired, bool weak, int success_memorder, int failure_memorder)
|
||||
{
|
||||
volatile uint64_t *val_ptr = (volatile uint64_t *)ptr;
|
||||
volatile uint64_t *expected_ptr = (volatile uint64_t *)expected;
|
||||
register rt_base_t level;
|
||||
bool exchanged;
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (*val_ptr == *expected_ptr)
|
||||
{
|
||||
*val_ptr = desired;
|
||||
exchanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*expected_ptr = *val_ptr;
|
||||
exchanged = false;
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
return exchanged;
|
||||
}
|
||||
|
||||
#define __atomic_fetch_op_8(OPNAME, OP) \
|
||||
uint64_t __atomic_fetch_##OPNAME##_8(volatile void *ptr, uint64_t val, int memorder) {\
|
||||
volatile uint64_t* val_ptr = (volatile uint64_t*)ptr;\
|
||||
register rt_base_t level;\
|
||||
uint64_t tmp;\
|
||||
level = rt_hw_interrupt_disable();\
|
||||
tmp = *val_ptr;\
|
||||
*val_ptr OP##= val;\
|
||||
rt_hw_interrupt_enable(level);\
|
||||
return tmp;\
|
||||
}
|
||||
|
||||
__atomic_fetch_op_8(add, +)
|
||||
__atomic_fetch_op_8(sub, -)
|
||||
__atomic_fetch_op_8( and, &)
|
||||
__atomic_fetch_op_8( or, |)
|
||||
__atomic_fetch_op_8(xor, ^)
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 peterfan Add copyright header.
|
||||
*/
|
||||
|
||||
/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||
* Source Licenses. See LICENSE.TXT for details.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define COMPILE_TIME_ASSERT(x)
|
||||
|
||||
extern int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));
|
||||
extern int pthread_key_delete(pthread_key_t key);
|
||||
extern void *pthread_getspecific(pthread_key_t key);
|
||||
extern int pthread_setspecific(pthread_key_t key, const void *value);
|
||||
|
||||
/* Default is not to use posix_memalign, so systems like Android
|
||||
* can use thread local data without heavier POSIX memory allocators.
|
||||
*/
|
||||
#ifndef EMUTLS_USE_POSIX_MEMALIGN
|
||||
#define EMUTLS_USE_POSIX_MEMALIGN 0
|
||||
#endif
|
||||
|
||||
/* For every TLS variable xyz,
|
||||
* there is one __emutls_control variable named __emutls_v.xyz.
|
||||
* If xyz has non-zero initial value, __emutls_v.xyz's "value"
|
||||
* will point to __emutls_t.xyz, which has the initial value.
|
||||
*/
|
||||
typedef struct __emutls_control
|
||||
{
|
||||
size_t size; /* size of the object in bytes */
|
||||
size_t align; /* alignment of the object in bytes */
|
||||
union
|
||||
{
|
||||
uintptr_t index; /* data[index-1] is the object address */
|
||||
void *address; /* object address, when in single thread env */
|
||||
} object;
|
||||
void *value; /* null or non-zero initial value for the object */
|
||||
} __emutls_control;
|
||||
|
||||
static __inline void *emutls_memalign_alloc(size_t align, size_t size)
|
||||
{
|
||||
void *base;
|
||||
#if EMUTLS_USE_POSIX_MEMALIGN
|
||||
if (posix_memalign(&base, align, size) != 0)
|
||||
abort();
|
||||
#else
|
||||
#define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void *))
|
||||
char *object;
|
||||
if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
|
||||
abort();
|
||||
base = (void *)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES)) & ~(uintptr_t)(align - 1));
|
||||
|
||||
((void **)base)[-1] = object;
|
||||
#endif
|
||||
return base;
|
||||
}
|
||||
|
||||
static __inline void emutls_memalign_free(void *base)
|
||||
{
|
||||
#if EMUTLS_USE_POSIX_MEMALIGN
|
||||
free(base);
|
||||
#else
|
||||
/* The mallocated address is in ((void**)base)[-1] */
|
||||
free(((void **)base)[-1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Emulated TLS objects are always allocated at run-time. */
|
||||
static __inline void *emutls_allocate_object(__emutls_control *control)
|
||||
{
|
||||
/* Use standard C types, check with gcc's emutls.o. */
|
||||
typedef unsigned int gcc_word __attribute__((mode(word)));
|
||||
typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
|
||||
COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word));
|
||||
COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
|
||||
COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void *));
|
||||
|
||||
size_t size = control->size;
|
||||
size_t align = control->align;
|
||||
if (align < sizeof(void *))
|
||||
align = sizeof(void *);
|
||||
/* Make sure that align is power of 2. */
|
||||
if ((align & (align - 1)) != 0)
|
||||
abort();
|
||||
|
||||
void *base = emutls_memalign_alloc(align, size);
|
||||
if (control->value)
|
||||
memcpy(base, control->value, size);
|
||||
else
|
||||
memset(base, 0, size);
|
||||
return base;
|
||||
}
|
||||
|
||||
static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static size_t emutls_num_object = 0; /* number of allocated TLS objects */
|
||||
|
||||
typedef struct emutls_address_array
|
||||
{
|
||||
uintptr_t size; /* number of elements in the 'data' array */
|
||||
void *data[];
|
||||
} emutls_address_array;
|
||||
|
||||
static pthread_key_t emutls_pthread_key;
|
||||
|
||||
static void emutls_key_destructor(void *ptr)
|
||||
{
|
||||
emutls_address_array *array = (emutls_address_array *)ptr;
|
||||
uintptr_t i;
|
||||
for (i = 0; i < array->size; ++i)
|
||||
{
|
||||
if (array->data[i])
|
||||
emutls_memalign_free(array->data[i]);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void emutls_init(void)
|
||||
{
|
||||
if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Returns control->object.index; set index if not allocated yet. */
|
||||
static __inline uintptr_t emutls_get_index(__emutls_control *control)
|
||||
{
|
||||
uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
|
||||
if (!index)
|
||||
{
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
pthread_once(&once, emutls_init);
|
||||
pthread_mutex_lock(&emutls_mutex);
|
||||
index = control->object.index;
|
||||
if (!index)
|
||||
{
|
||||
index = ++emutls_num_object;
|
||||
__atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
|
||||
}
|
||||
pthread_mutex_unlock(&emutls_mutex);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/* Updates newly allocated thread local emutls_address_array. */
|
||||
static __inline void emutls_check_array_set_size(emutls_address_array *array,
|
||||
uintptr_t size)
|
||||
{
|
||||
if (array == NULL)
|
||||
abort();
|
||||
array->size = size;
|
||||
pthread_setspecific(emutls_pthread_key, (void *)array);
|
||||
}
|
||||
|
||||
/* Returns the new 'data' array size, number of elements,
|
||||
* which must be no smaller than the given index.
|
||||
*/
|
||||
static __inline uintptr_t emutls_new_data_array_size(uintptr_t index)
|
||||
{
|
||||
/* Need to allocate emutls_address_array with one extra slot
|
||||
* to store the data array size.
|
||||
* Round up the emutls_address_array size to multiple of 16.
|
||||
*/
|
||||
return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
|
||||
}
|
||||
|
||||
/* Returns the thread local emutls_address_array.
|
||||
* Extends its size if necessary to hold address at index.
|
||||
*/
|
||||
static __inline emutls_address_array *
|
||||
emutls_get_address_array(uintptr_t index)
|
||||
{
|
||||
emutls_address_array *array = pthread_getspecific(emutls_pthread_key);
|
||||
if (array == NULL)
|
||||
{
|
||||
uintptr_t new_size = emutls_new_data_array_size(index);
|
||||
array = calloc(new_size + 1, sizeof(void *));
|
||||
emutls_check_array_set_size(array, new_size);
|
||||
}
|
||||
else if (index > array->size)
|
||||
{
|
||||
uintptr_t orig_size = array->size;
|
||||
uintptr_t new_size = emutls_new_data_array_size(index);
|
||||
array = realloc(array, (new_size + 1) * sizeof(void *));
|
||||
if (array)
|
||||
memset(array->data + orig_size, 0,
|
||||
(new_size - orig_size) * sizeof(void *));
|
||||
emutls_check_array_set_size(array, new_size);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
void *__emutls_get_address(void *control)
|
||||
{
|
||||
uintptr_t index = emutls_get_index((__emutls_control *)control);
|
||||
emutls_address_array *array = emutls_get_address_array(index);
|
||||
if (array->data[index - 1] == NULL)
|
||||
array->data[index - 1] = emutls_allocate_object((__emutls_control *)control);
|
||||
return array->data[index - 1];
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <system_error>
|
||||
#include <chrono>
|
||||
#include <ratio>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_USING_CPP_EXCEPTION
|
||||
|
||||
inline void throw_system_error(int err, const char *what_msg)
|
||||
{
|
||||
#ifdef RT_USING_CPP_EXCEPTION
|
||||
throw std::system_error(std::error_code(err, std::system_category()), what_msg);
|
||||
#else
|
||||
(void)err;
|
||||
(void)what_msg;
|
||||
::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
class tick_clock
|
||||
{
|
||||
public:
|
||||
typedef clock_t rep;
|
||||
typedef std::ratio<1, RT_TICK_PER_SECOND> period;
|
||||
|
||||
typedef std::chrono::duration<tick_clock::rep, tick_clock::period> duration;
|
||||
typedef std::chrono::time_point<tick_clock> time_point;
|
||||
|
||||
constexpr static bool is_ready = true;
|
||||
|
||||
static time_point now();
|
||||
};
|
||||
|
||||
class real_time_clock
|
||||
{
|
||||
public:
|
||||
typedef std::chrono::nanoseconds duration;
|
||||
typedef duration::rep rep;
|
||||
typedef duration::period period;
|
||||
typedef std::chrono::time_point<real_time_clock, duration> time_point;
|
||||
|
||||
static constexpr bool is_steady = true;
|
||||
|
||||
static time_point
|
||||
now() noexcept;
|
||||
};
|
||||
@@ -0,0 +1,222 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#error "C++ version lower than C++11"
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <system_error>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "__utils.h"
|
||||
#include "mutex"
|
||||
|
||||
#define rt_cpp_cond_var pthread_cond_t
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
enum class cv_status
|
||||
{
|
||||
no_timeout,
|
||||
timeout
|
||||
};
|
||||
|
||||
class condition_variable
|
||||
{
|
||||
public:
|
||||
typedef rt_cpp_cond_var *native_handle_type;
|
||||
|
||||
condition_variable(const condition_variable &) = delete;
|
||||
condition_variable &operator=(const condition_variable &) = delete;
|
||||
|
||||
condition_variable() = default;
|
||||
|
||||
~condition_variable()
|
||||
{
|
||||
pthread_cond_destroy(&_m_cond);
|
||||
}
|
||||
|
||||
void wait(unique_lock<mutex> &lock);
|
||||
|
||||
void notify_one() noexcept
|
||||
{
|
||||
pthread_cond_signal(&_m_cond);
|
||||
}
|
||||
|
||||
void notify_all() noexcept
|
||||
{
|
||||
pthread_cond_broadcast(&_m_cond);
|
||||
}
|
||||
|
||||
template <class Predicate>
|
||||
void wait(unique_lock<mutex> &lock, Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
wait(lock);
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
cv_status wait_until(unique_lock<mutex> &lock,
|
||||
const chrono::time_point<Clock, Duration> &abs_time)
|
||||
{
|
||||
if (!lock.owns_lock())
|
||||
throw_system_error((int)errc::operation_not_permitted,
|
||||
"condition_variable::wailt_until: waiting on unlocked lock");
|
||||
auto secs = chrono::time_point_cast<chrono::seconds>(abs_time);
|
||||
auto nano_secs = chrono::duration_cast<chrono::nanoseconds>(abs_time - secs);
|
||||
|
||||
struct timespec c_abs_time = {static_cast<time_t>(secs.time_since_epoch().count()),
|
||||
static_cast<long>(nano_secs.count())};
|
||||
|
||||
pthread_cond_timedwait(&_m_cond, lock.mutex()->native_handle(), &c_abs_time);
|
||||
|
||||
return (Clock::now() < abs_time) ? cv_status::no_timeout : cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration, class Predicate>
|
||||
bool wait_until(unique_lock<mutex> &lock,
|
||||
const chrono::time_point<Clock, Duration> &abs_time,
|
||||
Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
if (wait_until(lock, abs_time) == cv_status::timeout)
|
||||
return pred();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
cv_status wait_for(unique_lock<mutex> &lock,
|
||||
const chrono::duration<Rep, Period> &rel_time)
|
||||
{
|
||||
return wait_until(lock, real_time_clock::now() + rel_time);
|
||||
}
|
||||
|
||||
template <class Rep, class Period, class Predicate>
|
||||
bool wait_for(unique_lock<mutex> &lock,
|
||||
const chrono::duration<Rep, Period> &rel_time,
|
||||
Predicate pred)
|
||||
{
|
||||
return wait_until(lock, real_time_clock::now() + rel_time, std::move(pred));
|
||||
}
|
||||
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &_m_cond;
|
||||
}
|
||||
|
||||
private:
|
||||
rt_cpp_cond_var _m_cond = PTHREAD_COND_INITIALIZER;
|
||||
};
|
||||
|
||||
// Lockable is only required to have `lock()` and `unlock()`
|
||||
class condition_variable_any
|
||||
{
|
||||
private:
|
||||
condition_variable _m_cond;
|
||||
shared_ptr<mutex> _m_mtx;
|
||||
|
||||
// so that Lockable automatically unlocks when waiting and locks after waiting
|
||||
template <class Lockable>
|
||||
struct unlocker
|
||||
{
|
||||
Lockable &_m_lock;
|
||||
|
||||
explicit unlocker(Lockable &lk)
|
||||
: _m_lock(lk)
|
||||
{
|
||||
_m_lock.unlock();
|
||||
}
|
||||
|
||||
~unlocker()
|
||||
{
|
||||
_m_lock.lock();
|
||||
}
|
||||
|
||||
unlocker(const unlocker &) = delete;
|
||||
unlocker &operator=(const unlocker &) = delete;
|
||||
};
|
||||
|
||||
public:
|
||||
condition_variable_any() : _m_mtx(std::make_shared<mutex>()) {}
|
||||
~condition_variable_any() = default;
|
||||
|
||||
condition_variable_any(const condition_variable_any &) = delete;
|
||||
condition_variable_any &operator=(const condition_variable_any &) = delete;
|
||||
|
||||
void notify_one() noexcept
|
||||
{
|
||||
lock_guard<mutex> lk(*_m_mtx);
|
||||
_m_cond.notify_one();
|
||||
}
|
||||
|
||||
void notify_all() noexcept
|
||||
{
|
||||
lock_guard<mutex> lk(*_m_mtx);
|
||||
_m_cond.notify_all();
|
||||
}
|
||||
|
||||
template <class Lock>
|
||||
void wait(Lock &lock)
|
||||
{
|
||||
shared_ptr<mutex> mut = _m_mtx;
|
||||
unique_lock<mutex> lk(*mut);
|
||||
unlocker<Lock> auto_lk(lock); // unlock here
|
||||
|
||||
unique_lock<mutex> lk2(std::move(lk));
|
||||
_m_cond.wait(lk2);
|
||||
} // mut.unlock(); lock.lock();
|
||||
|
||||
template <class Lock, class Predicate>
|
||||
void wait(Lock &lock, Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
wait(lock);
|
||||
}
|
||||
|
||||
template <class Lock, class Clock, class Duration>
|
||||
cv_status wait_until(Lock &lock,
|
||||
const chrono::time_point<Clock, Duration> &abs_time)
|
||||
{
|
||||
shared_ptr<mutex> mut = _m_mtx;
|
||||
unique_lock<mutex> lk(*mut);
|
||||
unlocker<Lock> auto_lk(lock); // unlock here
|
||||
|
||||
unique_lock<mutex> lk2(std::move(lk));
|
||||
return _m_cond.wait_until(lk2, abs_time);
|
||||
}
|
||||
|
||||
template <class Lock, class Clock, class Duration, class Predicate>
|
||||
bool wait_until(Lock &lock,
|
||||
const chrono::time_point<Clock, Duration> &abs_time,
|
||||
Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
if (wait_until(lock, abs_time) == cv_status::timeout)
|
||||
return pred();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Lock, class Rep, class Period>
|
||||
cv_status wait_for(Lock &lock,
|
||||
const chrono::duration<Rep, Period> &rel_time)
|
||||
{
|
||||
return wait_until(lock, real_time_clock::now() + rel_time);
|
||||
}
|
||||
|
||||
template <class Lock, class Rep, class Period, class Predicate>
|
||||
bool wait_for(Lock &lock,
|
||||
const chrono::duration<Rep, Period> &rel_time,
|
||||
Predicate pred)
|
||||
{
|
||||
return wait_until(lock, real_time_clock::now() + rel_time, std::move(pred));
|
||||
}
|
||||
};
|
||||
|
||||
void notify_all_at_thread_exit(condition_variable &cond, unique_lock<mutex> lk);
|
||||
|
||||
} // namespace std
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include "condition_variable"
|
||||
|
||||
namespace std
|
||||
{
|
||||
void condition_variable::wait(unique_lock<mutex>& lock)
|
||||
{
|
||||
int err = pthread_cond_wait(&_m_cond, lock.mutex()->native_handle());
|
||||
|
||||
if (err)
|
||||
{
|
||||
throw_system_error(err, "condition_variable::wait: failed to wait on a condition");
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
|
||||
{
|
||||
// TLS currently not available
|
||||
mutex* mut = lk.release();
|
||||
mut->unlock();
|
||||
cond.notify_all();
|
||||
}
|
||||
|
||||
|
||||
} // namespace std
|
||||
@@ -0,0 +1,336 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#error "C++ version lower than C++11"
|
||||
#endif
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
|
||||
namespace std {
|
||||
|
||||
enum class future_status {
|
||||
ready,
|
||||
timeout,
|
||||
deferred
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
class shared_state_base {
|
||||
protected:
|
||||
typedef void (*deleter_fn)(void *v);
|
||||
|
||||
using scoped_lock = std::lock_guard<std::mutex>;
|
||||
using unique_lock = std::unique_lock<std::mutex>;
|
||||
public:
|
||||
explicit shared_state_base(deleter_fn d) : v_(nullptr), d_(d), valid_(true) {}
|
||||
|
||||
~shared_state_base() { d_(v_); }
|
||||
|
||||
shared_state_base(shared_state_base &&other) = delete;
|
||||
|
||||
shared_state_base(const shared_state_base &other) = delete;
|
||||
|
||||
shared_state_base &operator=(shared_state_base &&other) = delete;
|
||||
|
||||
shared_state_base &operator=(const shared_state_base &other) = delete;
|
||||
|
||||
void wait() {
|
||||
unique_lock lock(m_);
|
||||
c_.wait(lock, [this] { return has_value(); });
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
std::future_status
|
||||
wait_for(const std::chrono::duration<Rep, Period> &rel_time) {
|
||||
unique_lock lock(m_);
|
||||
if (c_.wait_for(lock, rel_time, [this] { return has_value(); })) {
|
||||
return std::future_status::ready;
|
||||
}
|
||||
return std::future_status::timeout;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
std::future_status
|
||||
wait_until(const std::chrono::time_point<Clock, Duration> &abs_time) {
|
||||
unique_lock lock(m_);
|
||||
if (c_.wait_until(lock, abs_time, [this] { return has_value(); })) {
|
||||
return std::future_status::ready;
|
||||
}
|
||||
return std::future_status::timeout;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool has_value() { return v_ != nullptr; }
|
||||
|
||||
protected:
|
||||
std::mutex m_;
|
||||
std::condition_variable c_;
|
||||
void *v_;
|
||||
deleter_fn d_;
|
||||
bool valid_;
|
||||
};
|
||||
|
||||
|
||||
template <typename R>
|
||||
class shared_state: public shared_state_base {
|
||||
public:
|
||||
shared_state() :shared_state_base(default_deleter_) {}
|
||||
|
||||
~shared_state() {}
|
||||
|
||||
R &get() {
|
||||
wait();
|
||||
scoped_lock lock(m_);
|
||||
assert(valid_);
|
||||
valid_ = false;
|
||||
return *(static_cast<R *>(v_));
|
||||
}
|
||||
|
||||
void set(const R &v) {
|
||||
scoped_lock lock(m_);
|
||||
assert(!has_value());
|
||||
v_ = new R(v);
|
||||
valid_ = true;
|
||||
c_.notify_one();
|
||||
}
|
||||
|
||||
void set(R &&v) {
|
||||
scoped_lock lock(m_);
|
||||
assert(!has_value());
|
||||
v_ = new R(std::move(v));
|
||||
valid_ = true;
|
||||
c_.notify_one();
|
||||
}
|
||||
|
||||
bool valid() {
|
||||
scoped_lock lock(m_);
|
||||
return valid_;
|
||||
}
|
||||
|
||||
private:
|
||||
static void default_deleter_(void *v) { delete static_cast<R *>(v); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename R>
|
||||
class shared_future {
|
||||
};
|
||||
|
||||
|
||||
template <typename R>
|
||||
class future {
|
||||
using state_type = std::shared_ptr<detail::shared_state<R>>;
|
||||
public:
|
||||
future() {}
|
||||
|
||||
explicit future(const state_type &state) : state_(state) {}
|
||||
|
||||
future(future &&other) noexcept: state_(std::move(other.state_)) {
|
||||
other.state_.reset();
|
||||
}
|
||||
|
||||
future(const future &other) = delete;
|
||||
|
||||
~future() {}
|
||||
|
||||
future &operator=(future &&other) noexcept {
|
||||
if (&other != this) {
|
||||
state_ = std::move(other.state_);
|
||||
other.state_.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
future &operator=(const future &other) = delete;
|
||||
|
||||
void swap(future &other) noexcept {
|
||||
std::swap(state_, other.state_);
|
||||
}
|
||||
|
||||
std::shared_future<R> share() noexcept { return std::shared_future<R>(); }
|
||||
|
||||
R get() { return state_->get(); }
|
||||
|
||||
bool valid() const noexcept { return state_->valid(); }
|
||||
|
||||
void wait() const { state_->wait(); }
|
||||
|
||||
template <class Rep, class Period>
|
||||
std::future_status
|
||||
wait_for(const std::chrono::duration<Rep, Period> &rel_time) const {
|
||||
return state_->wait_for(rel_time);
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
std::future_status
|
||||
wait_until(const std::chrono::time_point<Clock, Duration> &abs_time) const {
|
||||
return state_->wait_until(abs_time);
|
||||
}
|
||||
|
||||
private:
|
||||
state_type state_;
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
class future<void> {
|
||||
using state_type = std::shared_ptr<detail::shared_state<int>>;
|
||||
public:
|
||||
future() {}
|
||||
|
||||
explicit future(const state_type &state) : state_(state) {}
|
||||
|
||||
future(future &&other) noexcept: state_(std::move(other.state_)) {
|
||||
other.state_.reset();
|
||||
}
|
||||
|
||||
future(const future &other) = delete;
|
||||
|
||||
~future() {}
|
||||
|
||||
future &operator=(future &&other) noexcept {
|
||||
if (&other != this) {
|
||||
state_ = std::move(other.state_);
|
||||
other.state_.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
future &operator=(const future &other) = delete;
|
||||
|
||||
void swap(future &other) noexcept {
|
||||
std::swap(state_, other.state_);
|
||||
}
|
||||
|
||||
std::shared_future<void> share() noexcept { return std::shared_future<void>(); }
|
||||
|
||||
void get() { state_->get(); }
|
||||
|
||||
bool valid() const noexcept { return state_->valid(); }
|
||||
|
||||
void wait() const { state_->wait(); }
|
||||
|
||||
template <class Rep, class Period>
|
||||
std::future_status
|
||||
wait_for(const std::chrono::duration<Rep, Period> &rel_time) const {
|
||||
return state_->wait_for(rel_time);
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
std::future_status
|
||||
wait_until(const std::chrono::time_point<Clock, Duration> &abs_time) const {
|
||||
return state_->wait_until(abs_time);
|
||||
}
|
||||
|
||||
private:
|
||||
state_type state_;
|
||||
};
|
||||
|
||||
|
||||
template <typename R>
|
||||
class promise {
|
||||
using state_type = std::shared_ptr<detail::shared_state<R>>;
|
||||
public:
|
||||
promise() : state_(new detail::shared_state<R>()) {}
|
||||
|
||||
promise(promise &&other) noexcept: state_(std::move(other.state_)) {
|
||||
other.state_.reset();
|
||||
}
|
||||
|
||||
promise(const promise &other) = delete;
|
||||
|
||||
~promise() {}
|
||||
|
||||
promise &operator=(promise &&other) noexcept {
|
||||
if (&other != this) {
|
||||
state_ = std::move(other.state_);
|
||||
other.state_.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
promise &operator=(const promise &other) = delete;
|
||||
|
||||
void swap(promise &other) noexcept {
|
||||
std::swap(state_, other.state_);
|
||||
}
|
||||
|
||||
std::future<R> get_future() { return std::future<R>(state_); }
|
||||
|
||||
void set_value(const R &value) { state_->set(value); }
|
||||
|
||||
void set_value(R &&value) { state_->set(std::move(value)); }
|
||||
|
||||
void set_value_at_thread_exit(const R &value);
|
||||
|
||||
void set_value_at_thread_exit(R &&value);
|
||||
|
||||
void set_exception(std::exception_ptr p);
|
||||
|
||||
void set_exception_at_thread_exit(std::exception_ptr p);
|
||||
|
||||
private:
|
||||
state_type state_;
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
class promise<void> {
|
||||
using state_type = std::shared_ptr<detail::shared_state<int>>;
|
||||
public:
|
||||
promise() : state_(new detail::shared_state<int>()) {}
|
||||
|
||||
promise(promise &&other) noexcept: state_(std::move(other.state_)) {
|
||||
other.state_.reset();
|
||||
}
|
||||
|
||||
promise(const promise &other) = delete;
|
||||
|
||||
~promise() {}
|
||||
|
||||
promise &operator=(promise &&other) noexcept {
|
||||
if (&other != this) {
|
||||
state_ = std::move(other.state_);
|
||||
other.state_.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
promise &operator=(const promise &other) = delete;
|
||||
|
||||
void swap(promise &other) noexcept {
|
||||
std::swap(state_, other.state_);
|
||||
}
|
||||
|
||||
std::future<void> get_future() { return std::future<void>(state_); }
|
||||
|
||||
void set_value() { state_->set(0); }
|
||||
|
||||
void set_value_at_thread_exit();
|
||||
|
||||
void set_exception(std::exception_ptr p);
|
||||
|
||||
void set_exception_at_thread_exit(std::exception_ptr p);
|
||||
|
||||
private:
|
||||
state_type state_;
|
||||
};
|
||||
|
||||
|
||||
template <class R>
|
||||
void swap(std::future<R> &lhs, std::future<R> &rhs) noexcept {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template <class R>
|
||||
void swap(std::promise<R> &lhs, std::promise<R> &rhs) noexcept {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
@@ -0,0 +1,512 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#error "C++ version lower than C++11"
|
||||
#endif
|
||||
|
||||
//#if defined(RT_USING_PTHREADS)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <system_error>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
#include "__utils.h"
|
||||
|
||||
#define rt_cpp_mutex_t pthread_mutex_t
|
||||
|
||||
namespace std
|
||||
{
|
||||
// Base class on which to build std::mutex and std::timed_mutex
|
||||
class __mutex_base
|
||||
{
|
||||
protected:
|
||||
typedef rt_cpp_mutex_t __native_type;
|
||||
|
||||
__native_type _m_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
constexpr __mutex_base() noexcept = default;
|
||||
__mutex_base(const __mutex_base&) = delete;
|
||||
__mutex_base& operator=(const __mutex_base&) = delete;
|
||||
};
|
||||
|
||||
|
||||
class mutex : private __mutex_base
|
||||
{
|
||||
public:
|
||||
constexpr mutex() = default;
|
||||
~mutex() = default;
|
||||
|
||||
mutex(const mutex&) = delete;
|
||||
mutex& operator=(const mutex&) = delete;
|
||||
|
||||
void lock()
|
||||
{
|
||||
int err = pthread_mutex_lock(&_m_mutex);
|
||||
|
||||
if (err)
|
||||
{
|
||||
throw_system_error(err, "mutex:lock failed.");
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock() noexcept
|
||||
{
|
||||
return !pthread_mutex_trylock(&_m_mutex);
|
||||
}
|
||||
|
||||
void unlock() noexcept
|
||||
{
|
||||
pthread_mutex_unlock(&_m_mutex);
|
||||
}
|
||||
|
||||
typedef __native_type* native_handle_type;
|
||||
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &_m_mutex;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inline int __rt_cpp_recursive_mutex_init(rt_cpp_mutex_t* m)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int res;
|
||||
|
||||
res = pthread_mutexattr_init(&attr);
|
||||
if (res)
|
||||
return res;
|
||||
res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
if (res)
|
||||
goto attr_cleanup;
|
||||
res = pthread_mutex_init(m, &attr);
|
||||
|
||||
attr_cleanup:
|
||||
int err = pthread_mutexattr_destroy(&attr);
|
||||
return res ? res : err;
|
||||
}
|
||||
|
||||
class __recursive_mutex_base
|
||||
{
|
||||
protected:
|
||||
typedef rt_cpp_mutex_t __native_type;
|
||||
|
||||
__native_type _m_recursive_mutex;
|
||||
|
||||
__recursive_mutex_base(const __recursive_mutex_base&) = delete;
|
||||
__recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
|
||||
|
||||
__recursive_mutex_base()
|
||||
{
|
||||
int err = __rt_cpp_recursive_mutex_init(&_m_recursive_mutex);
|
||||
if (err)
|
||||
throw_system_error(err, "Recursive mutex failed to construct");
|
||||
}
|
||||
|
||||
~__recursive_mutex_base()
|
||||
{
|
||||
pthread_mutex_destroy(&_m_recursive_mutex);
|
||||
}
|
||||
};
|
||||
|
||||
class recursive_mutex : private __recursive_mutex_base
|
||||
{
|
||||
public:
|
||||
typedef __native_type* native_handle_type;
|
||||
recursive_mutex() = default;
|
||||
~recursive_mutex() = default;
|
||||
|
||||
recursive_mutex(const recursive_mutex&) = delete;
|
||||
recursive_mutex& operator=(const recursive_mutex&) = delete;
|
||||
void lock()
|
||||
{
|
||||
int err = pthread_mutex_lock(&_m_recursive_mutex);
|
||||
|
||||
if (err)
|
||||
throw_system_error(err, "recursive_mutex::lock failed");
|
||||
}
|
||||
|
||||
bool try_lock() noexcept
|
||||
{
|
||||
return !pthread_mutex_trylock(&_m_recursive_mutex);
|
||||
}
|
||||
|
||||
void unlock() noexcept
|
||||
{
|
||||
pthread_mutex_unlock(&_m_recursive_mutex);
|
||||
}
|
||||
|
||||
native_handle_type native_handle()
|
||||
{ return &_m_recursive_mutex; }
|
||||
};
|
||||
|
||||
#ifdef RT_PTHREAD_TIMED_MUTEX
|
||||
|
||||
class timed_mutex;
|
||||
|
||||
class recursive_timed_mutex;
|
||||
|
||||
#endif // RT_PTHREAD_TIMED_MUTEX
|
||||
|
||||
|
||||
struct defer_lock_t {};
|
||||
struct try_to_lock_t {};
|
||||
struct adopt_lock_t {}; // take ownership of a locked mtuex
|
||||
|
||||
constexpr defer_lock_t defer_lock { };
|
||||
constexpr try_to_lock_t try_to_lock { };
|
||||
constexpr adopt_lock_t adopt_lock { };
|
||||
|
||||
template <class Mutex>
|
||||
class lock_guard
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
explicit lock_guard(mutex_type& m) : pm(m) { pm.lock(); }
|
||||
lock_guard(mutex_type& m, adopt_lock_t) noexcept : pm(m)
|
||||
{ }
|
||||
~lock_guard()
|
||||
{ pm.unlock(); }
|
||||
|
||||
lock_guard(lock_guard const&) = delete;
|
||||
lock_guard& operator=(lock_guard const&) = delete;
|
||||
|
||||
private:
|
||||
mutex_type& pm;
|
||||
|
||||
};
|
||||
|
||||
template <class Mutex>
|
||||
class unique_lock
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
unique_lock() noexcept : pm(nullptr), owns(false) { }
|
||||
|
||||
explicit unique_lock(mutex_type& m)
|
||||
: pm(std::addressof(m)), owns(false)
|
||||
{
|
||||
lock();
|
||||
owns = true;
|
||||
}
|
||||
|
||||
unique_lock(mutex_type& m, defer_lock_t) noexcept
|
||||
: pm(std::addressof(m)), owns(false)
|
||||
{ }
|
||||
|
||||
unique_lock(mutex_type& m, try_to_lock_t) noexcept
|
||||
: pm(std::addressof(m)), owns(pm->try_lock())
|
||||
{ }
|
||||
|
||||
unique_lock(mutex_type& m, adopt_lock_t) noexcept
|
||||
: pm(std::addressof(m)), owns(true)
|
||||
{ }
|
||||
|
||||
// any lock-involving timed mutex API is currently only for custom implementations
|
||||
// the standard ones are not available
|
||||
template <class Clock, class Duration>
|
||||
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time) noexcept
|
||||
: pm(std::addressof(m)), owns(pm->try_lock_until(abs_time))
|
||||
{ }
|
||||
|
||||
template <class Rep, class Period>
|
||||
unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time) noexcept
|
||||
: pm(std::addressof(m)), owns(pm->try_lock_for(rel_time))
|
||||
{ }
|
||||
|
||||
~unique_lock()
|
||||
{
|
||||
if (owns)
|
||||
unlock();
|
||||
}
|
||||
|
||||
unique_lock(unique_lock const&) = delete;
|
||||
unique_lock& operator=(unique_lock const&) = delete;
|
||||
|
||||
unique_lock(unique_lock&& u) noexcept
|
||||
: pm(u.pm), owns(u.owns)
|
||||
{
|
||||
u.pm = nullptr;
|
||||
u.owns = false;
|
||||
}
|
||||
|
||||
unique_lock& operator=(unique_lock&& u) noexcept
|
||||
{
|
||||
if (owns)
|
||||
unlock();
|
||||
|
||||
unique_lock(std::move(u)).swap(*this);
|
||||
|
||||
u.pm = nullptr;
|
||||
u.owns = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (!pm)
|
||||
throw_system_error(int(errc::operation_not_permitted),
|
||||
"unique_lock::lock: references null mutex");
|
||||
else if (owns)
|
||||
throw_system_error(int(errc::resource_deadlock_would_occur),
|
||||
"unique_lock::lock: already locked" );
|
||||
else {
|
||||
pm->lock();
|
||||
owns = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
if (!pm)
|
||||
throw_system_error(int(errc::operation_not_permitted),
|
||||
"unique_lock::try_lock: references null mutex");
|
||||
else if (owns)
|
||||
throw_system_error(int(errc::resource_deadlock_would_occur),
|
||||
"unique_lock::try_lock: already locked" );
|
||||
else {
|
||||
owns = pm->try_lock();
|
||||
}
|
||||
return owns;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
if (!pm)
|
||||
throw_system_error(int(errc::operation_not_permitted),
|
||||
"unique_lock::try_lock_for: references null mutex");
|
||||
else if (owns)
|
||||
throw_system_error(int(errc::resource_deadlock_would_occur),
|
||||
"unique_lock::try_lock_for: already locked");
|
||||
else {
|
||||
owns = pm->try_lock_for(rel_time);
|
||||
}
|
||||
return owns;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
if (!pm)
|
||||
throw_system_error(int(errc::operation_not_permitted),
|
||||
"unique_lock::try_lock_until: references null mutex");
|
||||
else if (owns)
|
||||
throw_system_error(int(errc::resource_deadlock_would_occur),
|
||||
"unique_lock::try_lock_until: already locked");
|
||||
else {
|
||||
owns = pm->try_lock_until(abs_time);
|
||||
}
|
||||
return owns;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
if (!owns)
|
||||
throw_system_error(int(errc::operation_not_permitted),
|
||||
"unique_lock::unlock: not locked");
|
||||
else {
|
||||
pm->unlock();
|
||||
owns = false;
|
||||
}
|
||||
}
|
||||
|
||||
void swap(unique_lock& u) noexcept
|
||||
{
|
||||
std::swap(pm, u.pm);
|
||||
std::swap(owns, u.owns);
|
||||
}
|
||||
|
||||
mutex_type *release() noexcept
|
||||
{
|
||||
mutex_type* ret_mutex = pm;
|
||||
pm = nullptr;
|
||||
owns = false;
|
||||
|
||||
return ret_mutex;
|
||||
}
|
||||
|
||||
bool owns_lock() const noexcept
|
||||
{ return owns; }
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{ return owns_lock(); }
|
||||
|
||||
mutex_type* mutex() const noexcept
|
||||
{ return pm; }
|
||||
|
||||
|
||||
private:
|
||||
mutex_type *pm;
|
||||
bool owns;
|
||||
};
|
||||
|
||||
template <class Mutex>
|
||||
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
template <class L0, class L1>
|
||||
int try_lock(L0& l0, L1& l1)
|
||||
{
|
||||
unique_lock<L0> u0(l0, try_to_lock); // try to lock the first Lockable
|
||||
// using unique_lock since we don't want to unlock l0 manually if l1 fails to lock
|
||||
if (u0.owns_lock())
|
||||
{
|
||||
if (l1.try_lock()) // lock the second one
|
||||
{
|
||||
u0.release(); // do not let RAII of a unique_lock unlock l0
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template <class L0, class L1, class L2, class... L3>
|
||||
int try_lock(L0& l0, L1& l1, L2& l2, L3&... l3)
|
||||
{
|
||||
int r = 0;
|
||||
unique_lock<L0> u0(l0, try_to_lock);
|
||||
// automatically unlock is done through RAII of unique_lock
|
||||
if (u0.owns_lock())
|
||||
{
|
||||
r = try_lock(l1, l2, l3...);
|
||||
if (r == -1)
|
||||
u0.release();
|
||||
else
|
||||
++r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class L0, class L1, class L2, class ...L3>
|
||||
void
|
||||
__lock_first(int i, L0& l0, L1& l1, L2& l2, L3&... l3)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// we first lock the one that is the most difficult to lock
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
unique_lock<L0> u0(l0);
|
||||
i = try_lock(l1, l2, l3...);
|
||||
if (i == -1)
|
||||
{
|
||||
u0.release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
sched_yield();
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
unique_lock<L1> u1(l1);
|
||||
i = try_lock(l2, l3..., l0);
|
||||
if (i == -1)
|
||||
{
|
||||
u1.release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (i == sizeof...(L3) + 1) // all except l0 are locked
|
||||
i = 0;
|
||||
else
|
||||
i += 2; // since i was two-based above
|
||||
sched_yield();
|
||||
break;
|
||||
default:
|
||||
__lock_first(i - 2, l2, l3..., l0, l1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class L0, class L1>
|
||||
void lock(L0& l0, L1& l1)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
unique_lock<L0> u0(l0);
|
||||
if (l1.try_lock())
|
||||
{
|
||||
u0.release();
|
||||
break;
|
||||
}
|
||||
}
|
||||
sched_yield();
|
||||
// wait and try the other way
|
||||
{
|
||||
unique_lock<L1> u1(l1);
|
||||
if (l0.try_lock())
|
||||
{
|
||||
u1.release();
|
||||
break;
|
||||
}
|
||||
}
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
template <class L0, class L1, class... L2>
|
||||
void lock(L0& l0, L1& l1, L2&... l2)
|
||||
{
|
||||
__lock_first(0, l0, l1, l2...);
|
||||
}
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
constexpr once_flag() noexcept = default;
|
||||
|
||||
once_flag(const once_flag&) = delete;
|
||||
once_flag& operator=(const once_flag&) = delete;
|
||||
|
||||
template <class Callable, class... Args>
|
||||
friend void call_once(once_flag& flag, Callable&& func, Args&&... args);
|
||||
|
||||
private:
|
||||
pthread_once_t _m_once = PTHREAD_ONCE_INIT;
|
||||
};
|
||||
|
||||
mutex& get_once_mutex();
|
||||
extern function<void()> once_functor;
|
||||
extern void set_once_functor_lock_ptr(unique_lock<mutex>*);
|
||||
|
||||
extern "C" void once_proxy(); // passed into pthread_once
|
||||
|
||||
template <class Callable, class... Args>
|
||||
void call_once(once_flag& flag, Callable&& func, Args&&... args)
|
||||
{
|
||||
// use a lock to ensure the call to the functor
|
||||
// is exclusive to only the first calling thread
|
||||
unique_lock<mutex> functor_lock(get_once_mutex());
|
||||
|
||||
auto call_wrapper = std::bind(std::forward<Callable>(func), std::forward<Args>(args)...);
|
||||
once_functor = [&]() { call_wrapper(); };
|
||||
|
||||
set_once_functor_lock_ptr(&functor_lock); // so as to unlock when actually calling
|
||||
|
||||
int err = pthread_once(&flag._m_once, &once_proxy);
|
||||
|
||||
if (functor_lock)
|
||||
set_once_functor_lock_ptr(nullptr);
|
||||
if (err)
|
||||
throw_system_error(err, "call_once failed");
|
||||
}
|
||||
}
|
||||
|
||||
//#endif //(RT_USING_PTHREADS)
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include "mutex"
|
||||
|
||||
namespace std
|
||||
{
|
||||
// use a set of global and static objects
|
||||
// a proxy function to pthread_once
|
||||
|
||||
function<void()> once_functor;
|
||||
|
||||
mutex& get_once_mutex()
|
||||
{
|
||||
static mutex once_mutex;
|
||||
return once_mutex;
|
||||
}
|
||||
|
||||
inline unique_lock<mutex>*& get_once_functor_lock_ptr()
|
||||
{
|
||||
static unique_lock<mutex>* once_functor_mutex_ptr = nullptr;
|
||||
return once_functor_mutex_ptr;
|
||||
}
|
||||
|
||||
void set_once_functor_lock_ptr(unique_lock<mutex>* m_ptr)
|
||||
{
|
||||
get_once_functor_lock_ptr() = m_ptr;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void once_proxy()
|
||||
{
|
||||
// need to first transfer the functor's ownership so as to call it
|
||||
function<void()> once_call = std::move(once_functor);
|
||||
|
||||
// no need to hold the lock anymore
|
||||
unique_lock<mutex>* lock_ptr = get_once_functor_lock_ptr();
|
||||
get_once_functor_lock_ptr() = nullptr;
|
||||
lock_ptr->unlock();
|
||||
|
||||
once_call();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#error "C++ version lower than C++11"
|
||||
#endif
|
||||
|
||||
//#if defined(RT_USING_PTHREADS)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cerrno>
|
||||
#include <ostream>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#define rt_cpp_thread_t pthread_t
|
||||
#ifndef PTHREAD_NUM_MAX
|
||||
#define PTHREAD_NUM_MAX 32
|
||||
#endif
|
||||
#define CPP_UNJOINABLE_THREAD PTHREAD_NUM_MAX
|
||||
|
||||
namespace std
|
||||
{
|
||||
#define __STDCPP_THREADS__ __cplusplus
|
||||
|
||||
|
||||
|
||||
class thread
|
||||
{
|
||||
public:
|
||||
typedef rt_cpp_thread_t native_handle_type;
|
||||
|
||||
struct invoker_base;
|
||||
typedef shared_ptr<invoker_base> invoker_base_ptr;
|
||||
|
||||
class id
|
||||
{
|
||||
// basically a wrapper around native_handle_type
|
||||
native_handle_type __cpp_thread_t;
|
||||
|
||||
public:
|
||||
id() noexcept : __cpp_thread_t(CPP_UNJOINABLE_THREAD) {}
|
||||
|
||||
explicit id(native_handle_type hid)
|
||||
: __cpp_thread_t(hid) {}
|
||||
private:
|
||||
friend class thread;
|
||||
friend class hash<thread::id>;
|
||||
|
||||
friend bool operator==(thread::id x, thread::id y) noexcept;
|
||||
|
||||
friend bool operator<(thread::id x, thread::id y) noexcept;
|
||||
|
||||
template <class charT, class traits>
|
||||
friend basic_ostream<charT, traits>&
|
||||
operator<<(basic_ostream<charT, traits>& out, thread::id id);
|
||||
};
|
||||
|
||||
thread() noexcept = default;
|
||||
thread(const thread&) = delete;
|
||||
thread& operator=(const thread&) = delete;
|
||||
~thread();
|
||||
|
||||
template <class F, class ...Args>
|
||||
explicit thread(F&& f, Args&&... args)
|
||||
{
|
||||
start_thread(make_invoker_ptr(std::bind(
|
||||
std::forward<F>(f),
|
||||
std::forward<Args>(args)...
|
||||
)));
|
||||
}
|
||||
|
||||
thread(thread&& t) noexcept
|
||||
{
|
||||
swap(t);
|
||||
}
|
||||
|
||||
thread& operator=(thread&& t) noexcept
|
||||
{
|
||||
if (joinable())
|
||||
terminate();
|
||||
swap(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// member functions
|
||||
void swap(thread& t) noexcept
|
||||
{
|
||||
std::swap(_m_thr, t._m_thr);
|
||||
}
|
||||
|
||||
bool joinable() const noexcept
|
||||
{
|
||||
return (_m_thr.__cpp_thread_t < PTHREAD_NUM_MAX);
|
||||
}
|
||||
|
||||
void join();
|
||||
|
||||
void detach();
|
||||
|
||||
id get_id() const noexcept { return _m_thr; }
|
||||
|
||||
native_handle_type native_handle() { return _m_thr.__cpp_thread_t; }
|
||||
|
||||
// static members
|
||||
static unsigned hardware_concurrency() noexcept;
|
||||
|
||||
private:
|
||||
id _m_thr;
|
||||
|
||||
void start_thread(invoker_base_ptr b);
|
||||
public:
|
||||
struct invoker_base
|
||||
{
|
||||
invoker_base_ptr this_ptr;
|
||||
|
||||
virtual ~invoker_base() = default;
|
||||
|
||||
virtual void invoke() = 0;
|
||||
};
|
||||
|
||||
|
||||
template<typename Callable>
|
||||
struct invoker : public invoker_base
|
||||
{
|
||||
Callable func;
|
||||
|
||||
invoker(Callable&& F) : func(std::forward<Callable>(F)) { }
|
||||
|
||||
void invoke() { func(); }
|
||||
};
|
||||
|
||||
template <typename Callable>
|
||||
shared_ptr<invoker<Callable>> make_invoker_ptr(Callable&& F)
|
||||
{
|
||||
return std::make_shared<invoker<Callable>>(std::forward<Callable>(F));
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
inline void swap(thread& x, thread& y) noexcept
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
|
||||
inline bool operator==(thread::id x, thread::id y) noexcept
|
||||
{
|
||||
// From POSIX for pthread_equal:
|
||||
//"If either t1 or t2 are not valid thread IDs, the behavior is undefined."
|
||||
return x.__cpp_thread_t == y.__cpp_thread_t;
|
||||
}
|
||||
|
||||
inline bool operator!=(thread::id x, thread::id y) noexcept
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
inline bool operator<(thread::id x, thread::id y) noexcept
|
||||
{
|
||||
return x.__cpp_thread_t < y.__cpp_thread_t;
|
||||
}
|
||||
|
||||
inline bool operator<=(thread::id x, thread::id y) noexcept
|
||||
{
|
||||
return !(y < x);
|
||||
}
|
||||
|
||||
inline bool operator>(thread::id x, thread::id y) noexcept
|
||||
{
|
||||
return !(x <= y);
|
||||
}
|
||||
|
||||
inline bool operator>=(thread::id x, thread::id y) noexcept
|
||||
{
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
template <class charT, class traits>
|
||||
inline basic_ostream<charT, traits>&
|
||||
operator<<(basic_ostream<charT, traits>& out, thread::id id)
|
||||
{
|
||||
if (id == thread::id()) // id is invalid, representing no pthread
|
||||
out << "thread::id of a non-executing thread";
|
||||
else
|
||||
out << id.__cpp_thread_t;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct hash<thread::id>
|
||||
{
|
||||
typedef size_t result_type;
|
||||
typedef thread::id argument_type;
|
||||
size_t operator()(const thread::id& id) const noexcept
|
||||
{
|
||||
return hash<rt_cpp_thread_t>()(id.__cpp_thread_t);
|
||||
}
|
||||
};
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
inline thread::id get_id() noexcept
|
||||
{
|
||||
return thread::id(pthread_self());
|
||||
}
|
||||
|
||||
inline void yield() noexcept
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void sleep_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
if (rel_time <= rel_time.zero()) // less than zero, no need to sleep
|
||||
return;
|
||||
auto milli_secs = chrono::duration_cast<chrono::milliseconds>(rel_time);
|
||||
// the precision is limited by rt-thread thread API
|
||||
rt_thread_mdelay(milli_secs.count());
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
inline void sleep_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
auto now = Clock::now();
|
||||
if (abs_time > now)
|
||||
sleep_for(abs_time - now);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include "thread"
|
||||
#include "__utils.h"
|
||||
|
||||
|
||||
#define _RT_NPROCS 0
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static void* execute_native_thread_routine(void *p)
|
||||
{
|
||||
thread::invoker_base* t = static_cast<thread::invoker_base*>(p);
|
||||
thread::invoker_base_ptr local;
|
||||
local.swap(t->this_ptr); // tranfer the ownership of the invoker into the thread entry
|
||||
|
||||
local->invoke();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void thread::start_thread(invoker_base_ptr b)
|
||||
{
|
||||
auto raw_ptr = b.get();
|
||||
// transfer the ownership of the invoker to the new thread
|
||||
raw_ptr->this_ptr = std::move(b);
|
||||
int err = pthread_create(&_m_thr.__cpp_thread_t, NULL,
|
||||
&execute_native_thread_routine, raw_ptr);
|
||||
|
||||
if (err)
|
||||
{
|
||||
raw_ptr->this_ptr.reset();
|
||||
throw_system_error(err, "Failed to create a thread");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
{
|
||||
if (joinable()) // when either not joined or not detached
|
||||
terminate();
|
||||
}
|
||||
|
||||
void thread::join()
|
||||
{
|
||||
int err = EINVAL;
|
||||
|
||||
if (joinable())
|
||||
err = pthread_join(native_handle(), NULL);
|
||||
|
||||
if (err)
|
||||
{
|
||||
throw_system_error(err, "thread::join failed");
|
||||
}
|
||||
|
||||
_m_thr = id();
|
||||
}
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
int err = EINVAL;
|
||||
|
||||
if (joinable())
|
||||
err = pthread_detach(native_handle());
|
||||
if (err)
|
||||
{
|
||||
throw_system_error(err, "thread::detach failed");
|
||||
}
|
||||
|
||||
_m_thr = id();
|
||||
}
|
||||
|
||||
// TODO: not yet actually implemented.
|
||||
// The standard states that the returned value should only be considered a hint.
|
||||
unsigned thread::hardware_concurrency() noexcept
|
||||
{
|
||||
int __n = _RT_NPROCS;
|
||||
if (__n < 0)
|
||||
__n = 0;
|
||||
return __n;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include "__utils.h"
|
||||
#include <sys/time.h>
|
||||
|
||||
tick_clock::time_point tick_clock::now()
|
||||
{
|
||||
tick_clock::rep cur_tk = clock();
|
||||
tick_clock::duration cur_time(cur_tk);
|
||||
|
||||
return tick_clock::time_point(cur_time);
|
||||
}
|
||||
|
||||
real_time_clock::time_point real_time_clock::now() noexcept
|
||||
{
|
||||
timespec tp;
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
|
||||
return time_point(duration(std::chrono::seconds(tp.tv_sec))
|
||||
+ std::chrono::nanoseconds(tp.tv_nsec));
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 flybreak the first version.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <cstdlib>
|
||||
|
||||
typedef void (*destructor) (void *);
|
||||
|
||||
extern "C"
|
||||
int __cxa_thread_atexit_impl(destructor dtor, void* obj, void* dso_symbol)
|
||||
{
|
||||
pthread_key_t key_tmp;
|
||||
if (pthread_key_create(&key_tmp, dtor) != 0)
|
||||
abort();
|
||||
pthread_setspecific(key_tmp, obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)/*GCC*/
|
||||
#include <cxxabi.h>
|
||||
|
||||
extern"C"
|
||||
int __cxxabiv1::__cxa_thread_atexit(destructor dtor, void *obj, void *dso_handle)
|
||||
{
|
||||
return __cxa_thread_atexit_impl(dtor, obj, dso_handle);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "cxx_mutex.h"
|
||||
|
||||
using namespace rtthread;
|
||||
|
||||
Mutex::Mutex(const char *name)
|
||||
{
|
||||
rt_mutex_init(&mID, name, RT_IPC_FLAG_PRIO);
|
||||
}
|
||||
|
||||
bool Mutex::lock(int32_t millisec)
|
||||
{
|
||||
rt_int32_t tick;
|
||||
|
||||
if (millisec < 0)
|
||||
tick = -1;
|
||||
else
|
||||
tick = rt_tick_from_millisecond(millisec);
|
||||
|
||||
return rt_mutex_take(&mID, tick) == RT_EOK;
|
||||
}
|
||||
|
||||
bool Mutex::trylock()
|
||||
{
|
||||
return lock(0);
|
||||
}
|
||||
|
||||
void Mutex::unlock()
|
||||
{
|
||||
rt_mutex_release(&mID);
|
||||
}
|
||||
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
rt_mutex_detach(&mID);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "cxx_semaphore.h"
|
||||
|
||||
using namespace rtthread;
|
||||
|
||||
Semaphore::Semaphore(const char *name, int32_t count)
|
||||
{
|
||||
rt_sem_init(&mID, name, count, RT_IPC_FLAG_FIFO);
|
||||
}
|
||||
|
||||
bool Semaphore::wait(int32_t millisec)
|
||||
{
|
||||
rt_int32_t tick;
|
||||
|
||||
if (millisec < 0)
|
||||
tick = -1;
|
||||
else
|
||||
tick = rt_tick_from_millisecond(millisec);
|
||||
|
||||
return rt_sem_take(&mID, tick) == RT_EOK;
|
||||
}
|
||||
|
||||
void Semaphore::release(void)
|
||||
{
|
||||
rt_sem_release(&mID);
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
rt_sem_detach(&mID);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "cxx_thread.h"
|
||||
|
||||
using namespace rtthread;
|
||||
|
||||
Thread::Thread(rt_uint32_t stack_size,
|
||||
rt_uint8_t priority,
|
||||
rt_uint32_t tick,
|
||||
const char *name)
|
||||
: _entry(RT_NULL), _param(RT_NULL), started(false)
|
||||
{
|
||||
rt_event_init(&_event, name, 0);
|
||||
|
||||
_thread = rt_thread_create(name,
|
||||
(thread_func_t)func,
|
||||
this,
|
||||
stack_size,
|
||||
priority,
|
||||
tick);
|
||||
}
|
||||
|
||||
Thread::Thread(void (*entry)(void *p),
|
||||
void *p,
|
||||
rt_uint32_t stack_size,
|
||||
rt_uint8_t priority,
|
||||
rt_uint32_t tick,
|
||||
const char *name)
|
||||
: _entry(entry), _param(p), started(false)
|
||||
{
|
||||
rt_event_init(&_event, name, 0);
|
||||
|
||||
_thread = rt_thread_create(name,
|
||||
(thread_func_t)func,
|
||||
this,
|
||||
stack_size,
|
||||
priority,
|
||||
tick);
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
rt_event_detach(&_event);
|
||||
rt_thread_delete(_thread);
|
||||
}
|
||||
|
||||
bool Thread::start()
|
||||
{
|
||||
if (rt_thread_startup(_thread) == RT_EOK)
|
||||
{
|
||||
started = true;
|
||||
}
|
||||
|
||||
return started;
|
||||
}
|
||||
|
||||
void Thread::sleep(int32_t millisec)
|
||||
{
|
||||
rt_int32_t tick;
|
||||
|
||||
if (millisec < 0)
|
||||
tick = 1;
|
||||
else
|
||||
tick = rt_tick_from_millisecond(millisec);
|
||||
|
||||
rt_thread_delay(tick);
|
||||
}
|
||||
|
||||
void Thread::func(Thread *pThis)
|
||||
{
|
||||
if (pThis->_entry != RT_NULL)
|
||||
{
|
||||
pThis->_entry(pThis->_param);
|
||||
}
|
||||
else
|
||||
{
|
||||
pThis->run(pThis->_param);
|
||||
}
|
||||
|
||||
rt_event_send(&pThis->_event, 1);
|
||||
}
|
||||
|
||||
void Thread::run(void *parameter)
|
||||
{
|
||||
/* please overload this method */
|
||||
}
|
||||
|
||||
rt_err_t Thread::wait(int32_t millisec)
|
||||
{
|
||||
return join(millisec);
|
||||
}
|
||||
|
||||
rt_err_t Thread::join(int32_t millisec)
|
||||
{
|
||||
if (started)
|
||||
{
|
||||
rt_int32_t tick;
|
||||
|
||||
if (millisec < 0)
|
||||
tick = -1;
|
||||
else
|
||||
tick = rt_tick_from_millisecond(millisec);
|
||||
|
||||
return rt_event_recv(&_event, 1, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, tick, RT_NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-03-07 Bernard Add copyright header.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "cxx_crt.h"
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return rt_malloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return rt_malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
rt_free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr)
|
||||
{
|
||||
return rt_free(ptr);
|
||||
}
|
||||
|
||||
void __cxa_pure_virtual(void)
|
||||
{
|
||||
rt_kprintf("Illegal to call a pure virtual function.\n");
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-03-07 Bernard Add copyright header.
|
||||
*/
|
||||
|
||||
#ifndef CRT_H_
|
||||
#define CRT_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void *operator new(size_t size);
|
||||
void *operator new[](size_t size);
|
||||
|
||||
void operator delete(void * ptr);
|
||||
void operator delete[](void *ptr);
|
||||
|
||||
extern "C" void __cxa_pure_virtual(void);
|
||||
extern "C" int cplusplus_system_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-12-03 Bernard Add copyright header.
|
||||
* 2014-12-29 Bernard Add cplusplus initialization for ARMCC.
|
||||
* 2016-06-28 Bernard Add _init/_fini routines for GCC.
|
||||
* 2016-10-02 Bernard Add WEAK for cplusplus_system_init routine.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(__ARMCC_VERSION)
|
||||
extern void $Super$$__cpp_initialize__aeabi_(void);
|
||||
/* we need to change the cpp_initialize order */
|
||||
RT_WEAK void $Sub$$__cpp_initialize__aeabi_(void)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
#elif defined(__GNUC__) && !defined(__CS_SOURCERYGXX_MAJ__)
|
||||
/* The _init()/_fini() routines has been defined in codesourcery g++ lite */
|
||||
RT_WEAK void _init()
|
||||
{
|
||||
}
|
||||
|
||||
RT_WEAK void _fini()
|
||||
{
|
||||
}
|
||||
|
||||
RT_WEAK void *__dso_handle = 0;
|
||||
|
||||
#endif
|
||||
|
||||
RT_WEAK int cplusplus_system_init(void)
|
||||
{
|
||||
#if defined(__ARMCC_VERSION)
|
||||
/* If there is no SHT$$INIT_ARRAY, calling
|
||||
* $Super$$__cpp_initialize__aeabi_() will cause fault. At least until Keil5.12
|
||||
* the problem still exists. So we have to initialize the C++ runtime by ourself.
|
||||
*/
|
||||
typedef void PROC();
|
||||
extern const unsigned long SHT$$INIT_ARRAY$$Base[];
|
||||
extern const unsigned long SHT$$INIT_ARRAY$$Limit[];
|
||||
|
||||
const unsigned long *base = SHT$$INIT_ARRAY$$Base;
|
||||
const unsigned long *lim = SHT$$INIT_ARRAY$$Limit;
|
||||
|
||||
for (; base != lim; base++)
|
||||
{
|
||||
PROC *proc = (PROC *)((const char *)base + *base);
|
||||
(*proc)();
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
typedef void(*pfunc)();
|
||||
extern pfunc __ctors_start__[];
|
||||
extern pfunc __ctors_end__[];
|
||||
pfunc *p;
|
||||
|
||||
for (p = __ctors_start__; p < __ctors_end__; p++)
|
||||
(*p)();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(cplusplus_system_init);
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016/10/1 Bernard The first version
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace rtthread {
|
||||
|
||||
class Lock
|
||||
{
|
||||
public:
|
||||
Lock(Mutex& mutex) : m(mutex) {m.lock();}
|
||||
~Lock() {m.unlock();}
|
||||
|
||||
protected:
|
||||
Mutex &m;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016/10/1 Bernard The first version
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
namespace rtthread {
|
||||
|
||||
/**
|
||||
* The Mail class allow to control, send, receive, or wait for mail.
|
||||
* A mail is a memory block that is send to a thread or interrupt service routine.
|
||||
* @param T data type of a single message element.
|
||||
* @param queue_sz maximum number of messages in queue.
|
||||
*/
|
||||
|
||||
template<typename T, uint32_t queue_sz>
|
||||
class Mail {
|
||||
public:
|
||||
/** Create and Initialise Mail queue. */
|
||||
Mail(const char *name = "")
|
||||
{
|
||||
rt_mb_init(&mID, name, mPool, queue_sz, RT_IPC_FLAG_FIFO);
|
||||
}
|
||||
|
||||
~Mail()
|
||||
{
|
||||
rt_mb_detach(&mID);
|
||||
}
|
||||
|
||||
/** Put a mail in the queue.
|
||||
@param mptr memory block previously allocated with Mail::alloc or Mail::calloc.
|
||||
@return status code that indicates the execution status of the function.
|
||||
*/
|
||||
bool put(T *mptr, int32_t millisec = 0)
|
||||
{
|
||||
rt_int32_t tick;
|
||||
|
||||
if (millisec < 0)
|
||||
tick = -1;
|
||||
else
|
||||
tick = rt_tick_from_millisecond(millisec);
|
||||
|
||||
return rt_mb_send_wait(&mID, (rt_ubase_t)mptr, tick) == RT_EOK;
|
||||
}
|
||||
|
||||
/** Get a mail from a queue.
|
||||
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
|
||||
@return event that contains mail information or error code.
|
||||
*/
|
||||
T* get(int32_t millisec = -1)
|
||||
{
|
||||
T *t = NULL;
|
||||
rt_int32_t tick;
|
||||
|
||||
if (millisec < 0)
|
||||
tick = -1;
|
||||
else
|
||||
tick = rt_tick_from_millisecond(millisec);
|
||||
|
||||
rt_mb_recv(&mID, &t, tick);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
private:
|
||||
struct rt_mailbox mID;
|
||||
T* mPool[queue_sz];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016/10/1 Bernard The first version
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
namespace rtthread {
|
||||
|
||||
/** The Mutex class is used to synchronise the execution of threads.
|
||||
This is for example used to protect access to a shared resource.
|
||||
*/
|
||||
class Mutex {
|
||||
public:
|
||||
/** Create and Initialize a Mutex object */
|
||||
Mutex(const char *name = "mutex");
|
||||
~Mutex();
|
||||
|
||||
/** Wait until a Mutex becomes available.
|
||||
@param millisec timeout value or 0 in case of no time-out. (default: WaitForever)
|
||||
@return true if the mutex was acquired, false otherwise.
|
||||
*/
|
||||
bool lock(int32_t millisec = -1);
|
||||
|
||||
/** Try to lock the mutex, and return immediately
|
||||
@return true if the mutex was acquired, false otherwise.
|
||||
*/
|
||||
bool trylock();
|
||||
|
||||
/** Unlock the mutex that has previously been locked by the same thread
|
||||
*/
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
struct rt_mutex mID;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016/10/1 Bernard The first version
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
namespace rtthread {
|
||||
|
||||
/**
|
||||
* The Queue class allow to control, send, receive, or wait for messages.
|
||||
* A message can be a integer or pointer value to a certain type T that is send
|
||||
* to a thread or interrupt service routine.
|
||||
* @param T data type of a single message element.
|
||||
* @param queue_sz maximum number of messages in queue.
|
||||
*/
|
||||
template<typename T, uint32_t queue_sz>
|
||||
class Queue
|
||||
{
|
||||
public:
|
||||
/** Create and initialise a message Queue. */
|
||||
Queue()
|
||||
{
|
||||
rt_mq_init(&mID, "mq", mPool, sizeof(T), sizeof(mPool), RT_IPC_FLAG_FIFO);
|
||||
};
|
||||
|
||||
~Queue()
|
||||
{
|
||||
rt_mq_detach(&mID);
|
||||
};
|
||||
|
||||
/** Put a message in a Queue.
|
||||
@param data message pointer.
|
||||
@param millisec timeout value or 0 in case of no time-out. (default: 0)
|
||||
@return status code that indicates the execution status of the function.
|
||||
*/
|
||||
rt_err_t put(T& data, int32_t millisec = 0)
|
||||
{
|
||||
return rt_mq_send(&mID, &data, sizeof(data));
|
||||
}
|
||||
|
||||
/** Get a message or Wait for a message from a Queue.
|
||||
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
|
||||
@return bool .
|
||||
*/
|
||||
bool get(T& data, int32_t millisec = WAIT_FOREVER)
|
||||
{
|
||||
rt_int32_t tick;
|
||||
|
||||
if (millisec < 0)
|
||||
tick = -1;
|
||||
else
|
||||
tick = rt_tick_from_millisecond(millisec);
|
||||
|
||||
return rt_mq_recv(&mID, &data, sizeof(data), tick) == RT_EOK;
|
||||
}
|
||||
|
||||
private:
|
||||
struct rt_messagequeue mID;
|
||||
|
||||
char mPool[(sizeof(void *) + RT_ALIGN(sizeof(T), RT_ALIGN_SIZE)) * queue_sz];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016/10/1 Bernard The first version
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
namespace rtthread {
|
||||
|
||||
/** The Semaphore class is used to manage and protect access to a set of shared resources. */
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
/** Create and Initialize a Semaphore object used for managing resources.
|
||||
@param number of available resources; maximum index value is (count-1).
|
||||
*/
|
||||
Semaphore(const char *name = "sem", int32_t count = 0);
|
||||
~Semaphore();
|
||||
|
||||
/** Wait until a Semaphore resource becomes available.
|
||||
@param millisec timeout value or 0 in case of no time-out.
|
||||
@return true on success.
|
||||
*/
|
||||
bool wait(int32_t millisec = -1);
|
||||
|
||||
/** Release a Semaphore resource that was obtain with Semaphore::wait.
|
||||
*/
|
||||
void release(void);
|
||||
|
||||
private:
|
||||
struct rt_semaphore mID;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016/10/1 Bernard The first version
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
namespace rtthread
|
||||
{
|
||||
|
||||
/** The Thread class allow defining, creating, and controlling thread functions in the system. */
|
||||
class Thread
|
||||
{
|
||||
public:
|
||||
typedef void (*thread_func_t)(void *param);
|
||||
|
||||
/** Allocate a new thread without starting execution
|
||||
@param priority initial priority of the thread function. (default: osPriorityNormal).
|
||||
@param stack_size stack size (in bytes) requirements for the thread function. (default: DEFAULT_STACK_SIZE).
|
||||
@param stack_pointer pointer to the stack area to be used by this thread (default: NULL).
|
||||
*/
|
||||
Thread(rt_uint32_t stack_size = 2048,
|
||||
rt_uint8_t priority = (RT_THREAD_PRIORITY_MAX * 2) / 3,
|
||||
rt_uint32_t tick = 20,
|
||||
const char *name = "th");
|
||||
|
||||
Thread(void (*entry)(void *p),
|
||||
void *p = RT_NULL,
|
||||
rt_uint32_t stack_size = 2048,
|
||||
rt_uint8_t priority = (RT_THREAD_PRIORITY_MAX * 2) / 3,
|
||||
rt_uint32_t tick = 20,
|
||||
const char *name = "th");
|
||||
|
||||
virtual ~Thread();
|
||||
|
||||
bool start();
|
||||
|
||||
static void sleep(int32_t millisec);
|
||||
|
||||
rt_err_t wait(int32_t millisec);
|
||||
rt_err_t join(int32_t millisec = -1);
|
||||
|
||||
protected:
|
||||
virtual void run(void *parameter);
|
||||
|
||||
private:
|
||||
static void func(Thread *pThis);
|
||||
|
||||
rt_thread_t _thread;
|
||||
|
||||
thread_func_t _entry;
|
||||
void *_param;
|
||||
|
||||
/* event for thread join */
|
||||
struct rt_event _event;
|
||||
bool started;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
### The list of function support for POSIX 51 standard in the RT-Thread
|
||||
|
||||
<ctype.h>
|
||||
+ isalnum()
|
||||
+ isalpha()
|
||||
+ isblank()
|
||||
+ iscntrl()
|
||||
+ isdigit()
|
||||
+ isgraph()
|
||||
+ islower()
|
||||
+ isprint()
|
||||
+ ispunct()
|
||||
+ isspace()
|
||||
+ isupper()
|
||||
+ isxdigit()
|
||||
+ tolower()
|
||||
+ toupper()
|
||||
|
||||
<errno.h> -> Suggesting to use <sys/errno.h> instead of <errno.h> to be compatible with three compilation platforms of IAR Keil GCC at the same time.
|
||||
+ errno
|
||||
|
||||
<fcntl.h>
|
||||
+ open()
|
||||
|
||||
<fenv.h> ;the 'env' should combined with non-volatile devices
|
||||
+ feclearexcept()
|
||||
+ fegetenv()
|
||||
+ fegetexceptflag()
|
||||
+ fegetround()
|
||||
+ feholdexcept()
|
||||
+ feraiseexcept()
|
||||
+ fesetenv()
|
||||
+ fesetexceptflag()
|
||||
+ fesetround()
|
||||
+ fetestexcept()
|
||||
+ feupdateenv()
|
||||
|
||||
<inttypes.h>
|
||||
+ imaxabs()
|
||||
+ imaxdiv()
|
||||
+ strtoimax()
|
||||
+ strtoumax()
|
||||
|
||||
<locale.h>
|
||||
+ localeconv()
|
||||
+ setlocale()
|
||||
|
||||
<pthread.h>
|
||||
+ pthread_atfork()
|
||||
+ pthread_attr_destroy()
|
||||
+ pthread_attr_getdetachstate()
|
||||
+ pthread_attr_getguardsize()
|
||||
+ pthread_attr_getinheritsched()
|
||||
+ pthread_attr_getschedparam()
|
||||
+ pthread_attr_getschedpolicy()
|
||||
+ pthread_attr_getscope()
|
||||
+ pthread_attr_getstack()
|
||||
+ pthread_attr_getstackaddr()
|
||||
+ pthread_attr_getstacksize()
|
||||
+ pthread_attr_init()
|
||||
+ pthread_attr_setdetachstate()
|
||||
+ pthread_attr_setguardsize()
|
||||
+ pthread_attr_setinheritsched()
|
||||
+ pthread_attr_setschedparam()
|
||||
+ pthread_attr_setschedpolicy()
|
||||
+ pthread_attr_setscope()
|
||||
+ pthread_attr_setstack()
|
||||
+ pthread_attr_setstackaddr()
|
||||
+ pthread_attr_setstacksize()
|
||||
+ pthread_cancel()
|
||||
+ pthread_cleanup_pop()
|
||||
+ pthread_cleanup_push()
|
||||
+ pthread_cond_broadcast()
|
||||
+ pthread_cond_destroy()
|
||||
+ pthread_cond_init()
|
||||
+ pthread_cond_signal()
|
||||
+ pthread_cond_timedwait()
|
||||
+ pthread_cond_wait()
|
||||
+ pthread_condattr_destroy()
|
||||
+ pthread_condattr_getclock()
|
||||
+ pthread_condattr_init()
|
||||
+ pthread_condattr_setclock()
|
||||
+ pthread_create()
|
||||
+ pthread_detach()
|
||||
+ pthread_equal()
|
||||
+ pthread_exit()
|
||||
+ pthread_getcpuclockid()
|
||||
+ pthread_getconcurrency()
|
||||
+ pthread_getschedparam()
|
||||
+ pthread_getspecific()
|
||||
+ pthread_join()
|
||||
+ pthread_key_create()
|
||||
+ pthread_key_delete()
|
||||
+ pthread_mutex_destroy()
|
||||
+ pthread_mutex_getprioceiling()
|
||||
+ pthread_mutex_init()
|
||||
+ pthread_mutex_lock()
|
||||
+ pthread_mutex_setprioceiling()
|
||||
+ pthread_mutex_trylock()
|
||||
+ pthread_mutex_unlock()
|
||||
+ pthread_mutexattr_destroy()
|
||||
+ pthread_mutexattr_getprioceiling()
|
||||
+ pthread_mutexattr_getprotocol()
|
||||
+ pthread_mutexattr_gettype()
|
||||
+ pthread_mutexattr_init()
|
||||
+ pthread_mutexattr_setprioceiling()
|
||||
+ pthread_mutexattr_setprotocol()
|
||||
+ pthread_mutexattr_settype()
|
||||
+ pthread_once()
|
||||
+ pthread_self()
|
||||
+ pthread_setcancelstate()
|
||||
+ pthread_setcanceltype()
|
||||
+ pthread_setconcurrency()
|
||||
+ pthread_setschedparam()
|
||||
+ pthread_setschedprio()
|
||||
+ pthread_setspecific()
|
||||
+ pthread_testcancel()
|
||||
|
||||
<sched.h>
|
||||
+ sched_get_priority_max()
|
||||
+ sched_get_priority_min()
|
||||
+ sched_rr_get_interval()
|
||||
|
||||
<samaphore.h>
|
||||
+ sem_close()
|
||||
+ sem_destroy()
|
||||
+ sem_getvalue()
|
||||
+ sem_init()
|
||||
+ sem_open()
|
||||
+ sem_post()
|
||||
+ sem_timedwait()
|
||||
+ sem_trywait()
|
||||
+ sem_unlink()
|
||||
+ sem_wait()
|
||||
|
||||
<setjmp.h>
|
||||
+ longjmp()
|
||||
+ setjmp()
|
||||
|
||||
<signal.h> -> Suggesting to use <sys/signal.h> instead of <signal.h> to be compatible with three compilation platforms of IAR Keil GCC at the same time.
|
||||
+ kill()
|
||||
+ pthread_kill()
|
||||
+ pthread_sigmask()
|
||||
+ raise()
|
||||
+ sigaction()
|
||||
+ sigaddset()
|
||||
+ sigdelset()
|
||||
+ sigemptyset()
|
||||
+ sigfillset()
|
||||
+ sigismember()
|
||||
+ signal()
|
||||
+ sigpending()
|
||||
+ sigprocmask()
|
||||
- sigqueue()
|
||||
+ sigsuspend()
|
||||
+ sigtimedwait()
|
||||
+ sigwait()
|
||||
+ sigwaitinfo()
|
||||
|
||||
<stdarg.h>
|
||||
+ va_arg()
|
||||
+ va_copy()
|
||||
+ va_end()
|
||||
+ va_start()
|
||||
|
||||
<stdio.h>
|
||||
+ clearerr()
|
||||
+ fclose()
|
||||
- fdopen()
|
||||
+ feof()
|
||||
+ ferror()
|
||||
+ fflush()
|
||||
+ fgetc()
|
||||
+ fgets()
|
||||
+ fileno() ; GCC and IAR support, but Keil doesn't support
|
||||
- flockfile()
|
||||
+ fopen()
|
||||
+ fprintf()
|
||||
+ fputc()
|
||||
+ fputs()
|
||||
+ fread()
|
||||
+ freopen()
|
||||
+ fscanf()
|
||||
- ftrylockfile()
|
||||
- funlockfile()
|
||||
+ fwrite()
|
||||
+ getc()
|
||||
% getc_unlocked() ; thread safe in the default
|
||||
+ getchar()
|
||||
+ getchar_unlocked()
|
||||
+ gets()
|
||||
+ perror()
|
||||
+ printf()
|
||||
+ putc()
|
||||
% putc_unlocked() ; thread safe in the default
|
||||
+ putchar()
|
||||
% putchar_unlocked() ; thread safe in the default
|
||||
+ puts()
|
||||
+ scanf()
|
||||
+ setbuf()
|
||||
+ setvbuf()
|
||||
+ snprintf()
|
||||
+ sprintf()
|
||||
+ sscanf()
|
||||
+ stderr
|
||||
+ stdin
|
||||
+ stdout
|
||||
+ ungetc()
|
||||
+ vfprintf()
|
||||
+ vfscanf()
|
||||
+ vprintf()
|
||||
+ vscanf()
|
||||
+ vsnprintf()
|
||||
+ vsprintf()
|
||||
+ vsscanf()
|
||||
|
||||
<stdlib.h>
|
||||
+ abort()
|
||||
+ abs()
|
||||
+ atof()
|
||||
+ atoi()
|
||||
+ atol()
|
||||
+ atoll()
|
||||
+ bsearch()
|
||||
+ calloc()
|
||||
+ div()
|
||||
+ free()
|
||||
+ getenv()
|
||||
+ labs()
|
||||
+ ldiv()
|
||||
+ llabs()
|
||||
+ lldiv()
|
||||
+ malloc()
|
||||
+ qsort()
|
||||
+ rand()
|
||||
% rand_r() ; thread safe in the default
|
||||
+ realloc()
|
||||
- setenv() ;the 'env' should combined with non-volatile devices
|
||||
+ srand()
|
||||
+ strtod()
|
||||
+ strtof()
|
||||
+ strtol()
|
||||
+ strtold()
|
||||
+ strtoll()
|
||||
+ strtoul()
|
||||
+ strtoull()
|
||||
- unsetenv() ;the 'env' should combined with non-volatile devices
|
||||
|
||||
<string.h>
|
||||
+ memchr()
|
||||
+ memcmp()
|
||||
+ memcpy()
|
||||
+ memmove()
|
||||
+ memset()
|
||||
+ strcat()
|
||||
+ strchr()
|
||||
+ strcmp()
|
||||
+ strcoll()
|
||||
+ strcpy()
|
||||
+ strcspn()
|
||||
+ strerror()
|
||||
% strerror_r() ; thread safe in the default
|
||||
+ strlen()
|
||||
+ strncat()
|
||||
+ strncmp()
|
||||
+ strncpy()
|
||||
+ strpbrk()
|
||||
+ strrchr()
|
||||
+ strspn()
|
||||
+ strstr()
|
||||
+ strtok()
|
||||
% strtok_r() ; thread safe in the default
|
||||
+ strxfrm()
|
||||
|
||||
<sys/mman.h>
|
||||
- mlockall()
|
||||
+ mmap()
|
||||
- munlock()
|
||||
+ munmap()
|
||||
- shm_open()
|
||||
- shm_unlink()
|
||||
|
||||
<sys/utsname.h>
|
||||
+ uname()
|
||||
|
||||
<time.h> -> Suggesting to use <sys/time.h> instead of <time.h> to be compatible with three compilation platforms of IAR Keil GCC at the same time.
|
||||
+ asctime()
|
||||
+ asctime_r()
|
||||
+ clock_getres()
|
||||
+ clock_gettime()
|
||||
+ clock_nanosleep()
|
||||
+ clock_settime()
|
||||
+ ctime()
|
||||
+ ctime_r()
|
||||
+ difftime()
|
||||
+ gmtime()
|
||||
+ gmtime_r()
|
||||
+ localtime()
|
||||
+ localtime_r()
|
||||
+ mktime()
|
||||
+ nanosleep()
|
||||
+ strftime()
|
||||
+ time()
|
||||
+ timer_create()
|
||||
+ timer_delete()
|
||||
+ timer_getoverrun()
|
||||
+ timer_gettime()
|
||||
+ timer_settime()
|
||||
- tzname ; you should better use 'tz_xxx' in the rt-thread.
|
||||
- tzset() ; you should better use 'tz_xxx' in the rt-thread.
|
||||
|
||||
<unistd.h>
|
||||
+ alarm()
|
||||
+ close()
|
||||
+ environ
|
||||
% fdatasync() ;smaller ranther than <fsync>, in the rt-thread, it is universal
|
||||
+ fsync()
|
||||
+ pause()
|
||||
+ read()
|
||||
+ sysconf()
|
||||
+ write()
|
||||
- confstr()
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
menu "POSIX (Portable Operating System Interface) layer"
|
||||
|
||||
config RT_USING_POSIX_FS
|
||||
bool "Enable POSIX file system and I/O"
|
||||
select RT_USING_DFS
|
||||
select DFS_USING_POSIX
|
||||
default n
|
||||
|
||||
if RT_USING_POSIX_FS
|
||||
config RT_USING_POSIX_DEVIO
|
||||
bool "Enable devices as file descriptors"
|
||||
select RT_USING_DFS_DEVFS
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_STDIO
|
||||
bool "Enable standard I/O devices, e.g. STDOUT_FILENO"
|
||||
select RT_USING_POSIX_DEVIO
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_POLL
|
||||
bool "Enable I/O Multiplexing poll() <poll.h>"
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_SELECT
|
||||
bool "Enable I/O Multiplexing select() <sys/select.h>"
|
||||
select RT_USING_POSIX_POLL
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_SOCKET
|
||||
bool "Enable BSD Socket I/O <sys/socket.h> <netdb.h>"
|
||||
select RT_USING_POSIX_SELECT
|
||||
select RT_USING_SAL
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_TERMIOS
|
||||
bool "Enable Terminal I/O <termios.h>"
|
||||
select RT_USING_POSIX_STDIO
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_AIO
|
||||
bool "Enable Asynchronous I/O <aio.h>"
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_MMAN
|
||||
bool "Enable Memory-Mapped I/O <sys/mman.h>"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_POSIX_DELAY
|
||||
bool "Enable delay APIs, sleep()/usleep()/msleep() etc"
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_CLOCK
|
||||
bool "Enable clock/time APIs, clock_gettime()/clock_settime() etc"
|
||||
select RT_USING_POSIX_DELAY
|
||||
default n
|
||||
|
||||
config RT_USING_POSIX_TIMER
|
||||
select RT_USING_TIMER_SOFT
|
||||
bool "Enable timer APIs, timer_create()/timer_gettime() etc"
|
||||
default n
|
||||
|
||||
config RT_USING_PTHREADS
|
||||
bool "Enable pthreads APIs"
|
||||
select RT_USING_POSIX_CLOCK
|
||||
default n
|
||||
|
||||
if RT_USING_PTHREADS
|
||||
config PTHREAD_NUM_MAX
|
||||
int "Maximum number of pthreads"
|
||||
default 8
|
||||
endif
|
||||
|
||||
config RT_USING_MODULE
|
||||
bool "Enable dynamic module APIs, dlopen()/dlsym()/dlclose() etc"
|
||||
default n
|
||||
|
||||
if RT_USING_MODULE
|
||||
config RT_USING_CUSTOM_DLMODULE
|
||||
bool "Enable load dynamic module by custom"
|
||||
default n
|
||||
endif
|
||||
|
||||
source "$RTT_DIR/components/libc/posix/ipc/Kconfig"
|
||||
|
||||
endmenu
|
||||
@@ -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')
|
||||
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('POSIX', src, depend = ['RT_USING_POSIX_DELAY'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-05-07 Meco Man first Version
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#define DBG_TAG "POSIX.delay"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
RT_WEAK void rt_hw_us_delay(rt_uint32_t us)
|
||||
{
|
||||
(void) us;
|
||||
LOG_W("Please consider implementing rt_hw_us_delay() in another file.");
|
||||
}
|
||||
|
||||
void msleep(unsigned int msecs)
|
||||
{
|
||||
rt_thread_mdelay(msecs);
|
||||
}
|
||||
RTM_EXPORT(msleep);
|
||||
|
||||
void ssleep(unsigned int seconds)
|
||||
{
|
||||
msleep(seconds * 1000);
|
||||
}
|
||||
RTM_EXPORT(ssleep);
|
||||
|
||||
void mdelay(unsigned long msecs)
|
||||
{
|
||||
rt_hw_us_delay(msecs * 1000);
|
||||
}
|
||||
RTM_EXPORT(mdelay);
|
||||
|
||||
void udelay(unsigned long usecs)
|
||||
{
|
||||
rt_hw_us_delay(usecs);
|
||||
}
|
||||
RTM_EXPORT(udelay);
|
||||
|
||||
void ndelay(unsigned long nsecs)
|
||||
{
|
||||
rt_hw_us_delay(1);
|
||||
}
|
||||
RTM_EXPORT(ndelay);
|
||||
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
{
|
||||
ssleep(seconds);
|
||||
}
|
||||
else /* scheduler has not run yet */
|
||||
{
|
||||
while(seconds > 0)
|
||||
{
|
||||
udelay(1000000u);
|
||||
seconds --;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
RTM_EXPORT(sleep);
|
||||
|
||||
int usleep(useconds_t usec)
|
||||
{
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
{
|
||||
msleep(usec / 1000u);
|
||||
}
|
||||
else /* scheduler has not run yet */
|
||||
{
|
||||
udelay(usec / 1000u);
|
||||
}
|
||||
udelay(usec % 1000u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
RTM_EXPORT(usleep);
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-05-07 Meco Man first Version
|
||||
*/
|
||||
|
||||
#ifndef __DELAY_H__
|
||||
#define __DELAY_H__
|
||||
|
||||
unsigned int sleep(unsigned int seconds);
|
||||
void msleep(unsigned int msecs);
|
||||
void ssleep(unsigned int seconds);
|
||||
void mdelay(unsigned long msecs);
|
||||
void udelay(unsigned long usecs);
|
||||
void ndelay(unsigned long nsecs);
|
||||
|
||||
#endif
|
||||
@@ -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 |
|
||||
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* 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_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
|
||||
* <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);
|
||||
@@ -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
|
||||
@@ -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')
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 <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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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')
|
||||
@@ -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)
|
||||
{
|
||||
rt_thread_suspend(thread);
|
||||
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_fd *f = fd_get(fd);
|
||||
mask = POLLNVAL;
|
||||
|
||||
if (f)
|
||||
{
|
||||
mask = POLLMASK_DEFAULT;
|
||||
if (f->fops->poll)
|
||||
{
|
||||
req->_key = pollfd->events | POLLERR | POLLHUP;
|
||||
|
||||
mask = f->fops->poll(f, req);
|
||||
|
||||
/* dealwith the device return error -1*/
|
||||
if (mask < 0)
|
||||
{
|
||||
fd_put(f);
|
||||
pollfd->revents = 0;
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
/* Mask out unneeded events. */
|
||||
mask &= pollfd->events | POLLERR | POLLHUP;
|
||||
fd_put(f);
|
||||
}
|
||||
}
|
||||
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;
|
||||
int 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;
|
||||
}
|
||||
Loaded 100 of 2473 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user