mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(freertos): soft-preempting linux simulator
This commit is contained in:
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Cooperative wrappers for Linux FreeRTOS simulator.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <poll.h>
|
||||
#include <dlfcn.h>
|
||||
#include <time.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#define COOP_SYSCALLS_WAIT_MS (1000 / CONFIG_FREERTOS_HZ)
|
||||
|
||||
extern bool linux_port_in_freertos_task(void);
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void coop_set_fd_nonblocking(int fd)
|
||||
{
|
||||
if (fd >= 0) {
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags >= 0) {
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void coop_wait(int ms)
|
||||
{
|
||||
if (linux_port_in_freertos_task()) {
|
||||
vTaskDelay(ms);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = ms / 1000;
|
||||
ts.tv_nsec = (ms % 1000) * 1000000L;
|
||||
while (nanosleep(&ts, &ts) == -1 && errno == EINTR) {
|
||||
// Retry with remaining time if interrupted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generic cooperative loop template */
|
||||
#define COOP_LOOP(start_expr) \
|
||||
while (1) \
|
||||
{ \
|
||||
ssize_t n = start_expr; \
|
||||
if (n >= 0) { \
|
||||
return n; \
|
||||
} else if (errno == EAGAIN || errno == EWOULDBLOCK) { \
|
||||
coop_wait(COOP_SYSCALLS_WAIT_MS); \
|
||||
continue; \
|
||||
} else { \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
ssize_t __real_read(int fd, void *buf, size_t count);
|
||||
ssize_t __real_write(int fd, const void *buf, size_t count);
|
||||
ssize_t __real_pread(int fd, void *buf, size_t count, off_t offset);
|
||||
ssize_t __real_pwrite(int fd, const void *buf, size_t count, off_t offset);
|
||||
ssize_t __real_readv(int fd, const struct iovec *iov, int iovcnt);
|
||||
ssize_t __real_writev(int fd, const struct iovec *iov, int iovcnt);
|
||||
ssize_t __real_recv(int sockfd, void *buf, size_t len, int flags);
|
||||
ssize_t __real_send(int sockfd, const void *buf, size_t len, int flags);
|
||||
ssize_t __real_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
ssize_t __real_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
ssize_t __real_recvmsg(int sockfd, struct msghdr *msg, int flags);
|
||||
ssize_t __real_sendmsg(int sockfd, const struct msghdr *msg, int flags);
|
||||
int __real_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int __real_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
int __real_close(int fd);
|
||||
int __real_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
|
||||
int __real_pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);
|
||||
int __real_poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
unsigned int __real_sleep(unsigned int seconds);
|
||||
int __real_usleep(useconds_t usec);
|
||||
|
||||
int __real_socket(int domain, int type, int protocol);
|
||||
int __real_socketpair(int domain, int type, int protocol, int sv[2]);
|
||||
int __real_pipe(int fds[2]);
|
||||
int __real_pipe2(int fds[2], int flags);
|
||||
int __real_dup(int oldfd);
|
||||
int __real_dup2(int oldfd, int newfd);
|
||||
int __real_open(const char *path, int flags, ...);
|
||||
|
||||
ssize_t __wrap_read(int fd, void *buf, size_t count)
|
||||
{
|
||||
COOP_LOOP(__real_read(fd, buf, count))
|
||||
}
|
||||
|
||||
ssize_t __wrap_write(int fd, const void *buf, size_t count)
|
||||
{
|
||||
COOP_LOOP(__real_write(fd, buf, count))
|
||||
}
|
||||
|
||||
ssize_t __wrap_pread(int fd, void *buf, size_t count, off_t offset)
|
||||
{
|
||||
COOP_LOOP(__real_pread(fd, buf, count, offset))
|
||||
}
|
||||
|
||||
ssize_t __wrap_pwrite(int fd, const void *buf, size_t count, off_t offset)
|
||||
{
|
||||
COOP_LOOP(__real_pwrite(fd, buf, count, offset))
|
||||
}
|
||||
|
||||
ssize_t __wrap_readv(int fd, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
COOP_LOOP(__real_readv(fd, iov, iovcnt))
|
||||
}
|
||||
|
||||
ssize_t __wrap_writev(int fd, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
COOP_LOOP(__real_writev(fd, iov, iovcnt))
|
||||
}
|
||||
|
||||
ssize_t __wrap_recv(int sockfd, void *buf, size_t len, int flags)
|
||||
{
|
||||
COOP_LOOP(__real_recv(sockfd, buf, len, flags | MSG_DONTWAIT))
|
||||
}
|
||||
|
||||
ssize_t __wrap_send(int sockfd, const void *buf, size_t len, int flags)
|
||||
{
|
||||
COOP_LOOP(__real_send(sockfd, buf, len, flags | MSG_DONTWAIT))
|
||||
}
|
||||
|
||||
ssize_t __wrap_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
|
||||
{
|
||||
COOP_LOOP(__real_recvfrom(sockfd, buf, len, flags | MSG_DONTWAIT, src_addr, addrlen))
|
||||
}
|
||||
|
||||
ssize_t __wrap_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||
{
|
||||
COOP_LOOP(__real_sendto(sockfd, buf, len, flags | MSG_DONTWAIT, dest_addr, addrlen))
|
||||
}
|
||||
|
||||
ssize_t __wrap_recvmsg(int sockfd, struct msghdr *msg, int flags)
|
||||
{
|
||||
COOP_LOOP(__real_recvmsg(sockfd, msg, flags | MSG_DONTWAIT))
|
||||
}
|
||||
|
||||
ssize_t __wrap_sendmsg(int sockfd, const struct msghdr *msg, int flags)
|
||||
{
|
||||
COOP_LOOP(__real_sendmsg(sockfd, msg, flags | MSG_DONTWAIT))
|
||||
}
|
||||
|
||||
int __wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int ret = __real_connect(sockfd, addr, addrlen);
|
||||
if (ret == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (errno == EINPROGRESS || errno == EALREADY) {
|
||||
/* Poll for writability (use __real_poll in cooperative loop,
|
||||
but do not block the kernel thread). We'll emulate blocking
|
||||
by repeatedly polling with 0 timeout and yielding. */
|
||||
struct pollfd pfd;
|
||||
pfd.fd = sockfd;
|
||||
pfd.events = POLLOUT;
|
||||
pfd.revents = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int press = __real_poll(&pfd, 1, 0);
|
||||
if (press > 0) {
|
||||
/* socket reported an event; check if connect succeeded */
|
||||
int so_err = 0;
|
||||
socklen_t len = sizeof(so_err);
|
||||
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_err, &len) < 0) {
|
||||
/* getsockopt failed; treat as error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (so_err == 0) {
|
||||
return 0; /* connected */
|
||||
} else {
|
||||
errno = so_err;
|
||||
return -1;
|
||||
}
|
||||
} else if (press == 0) {
|
||||
/* no event yet -> yield cooperatively and retry */
|
||||
coop_wait(COOP_SYSCALLS_WAIT_MS);
|
||||
continue;
|
||||
} else {
|
||||
/* press < 0 */
|
||||
if (errno == EINTR) {
|
||||
continue; /* retry poll */
|
||||
}
|
||||
|
||||
/* treat other errors as transient and yield */
|
||||
coop_wait(COOP_SYSCALLS_WAIT_MS);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errno == EINTR) {
|
||||
/* POSIX: connect may fail with EINTR; return -1 with errno==EINTR */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* other fatal errors */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int __wrap_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
COOP_LOOP(__real_accept(sockfd, addr, addrlen))
|
||||
}
|
||||
|
||||
int __wrap_close(int fd)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int ret = __real_close(fd);
|
||||
if (ret == 0) {
|
||||
return 0;
|
||||
} else if (errno == EINTR) {
|
||||
coop_wait(COOP_SYSCALLS_WAIT_MS);
|
||||
continue;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __wrap_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
|
||||
{
|
||||
/* compute timeout in milliseconds; -1 => infinite */
|
||||
long timeout_ms = -1;
|
||||
if (timeout != NULL) {
|
||||
/* convert timeval -> ms, rounding up microseconds */
|
||||
timeout_ms = (long)timeout->tv_sec * 1000 + (timeout->tv_usec + 999) / 1000;
|
||||
if (timeout_ms == 0) {
|
||||
/* immediate poll: call real_select with provided timeout */
|
||||
return __real_select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
long waited_ms = 0;
|
||||
while (1)
|
||||
{
|
||||
/* nonblocking check */
|
||||
struct timeval zero_tv = {0, 0};
|
||||
int ret = __real_select(nfds, readfds, writefds, exceptfds, &zero_tv);
|
||||
if (ret != 0) {
|
||||
/* ret > 0 => ready; ret < 0 => error and errno set */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* no descriptors ready */
|
||||
if (timeout_ms == 0) {
|
||||
return 0; /* expired */
|
||||
}
|
||||
|
||||
/* check timeout expiration */
|
||||
if (timeout_ms > 0 && waited_ms >= timeout_ms) {
|
||||
return 0; /* timeout expired */
|
||||
}
|
||||
|
||||
/* yield cooperatively */
|
||||
coop_wait(COOP_SYSCALLS_WAIT_MS);
|
||||
waited_ms += COOP_SYSCALLS_WAIT_MS;
|
||||
}
|
||||
}
|
||||
|
||||
int __wrap_pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
const struct timespec *timeout, const sigset_t *sigmask)
|
||||
{
|
||||
/* convert timespec -> ms, -1 for infinite */
|
||||
long timeout_ms = -1;
|
||||
if (timeout != NULL) {
|
||||
timeout_ms = (long)timeout->tv_sec * 1000 + (timeout->tv_nsec + 999999) / 1000000;
|
||||
if (timeout_ms == 0) {
|
||||
/* immediate poll: call real_pselect with provided timeout */
|
||||
return __real_pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask);
|
||||
}
|
||||
}
|
||||
|
||||
long waited_ms = 0;
|
||||
while (1)
|
||||
{
|
||||
struct timespec zero_ts = {0, 0};
|
||||
int ret = __real_pselect(nfds, readfds, writefds, exceptfds, &zero_ts, sigmask);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (timeout_ms == 0 ||
|
||||
(timeout_ms > 0 && waited_ms >= timeout_ms)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
coop_wait(COOP_SYSCALLS_WAIT_MS);
|
||||
waited_ms += COOP_SYSCALLS_WAIT_MS;
|
||||
}
|
||||
}
|
||||
|
||||
int __wrap_poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
||||
{
|
||||
if (timeout == 0) {
|
||||
/* immediate poll: delegate */
|
||||
return __real_poll(fds, nfds, 0);
|
||||
}
|
||||
|
||||
/* compute wait semantics */
|
||||
long timeout_ms = -1;
|
||||
if (timeout > 0) {
|
||||
timeout_ms = timeout;
|
||||
}
|
||||
|
||||
long waited_ms = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int ret = __real_poll(fds, nfds, 0);
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
/* no event; check timeout */
|
||||
if (timeout_ms == 0 ||
|
||||
(timeout_ms > 0 && waited_ms >= timeout_ms)) {
|
||||
return 0; /* expired */
|
||||
}
|
||||
|
||||
/* yield and continue */
|
||||
coop_wait(COOP_SYSCALLS_WAIT_MS);
|
||||
waited_ms += COOP_SYSCALLS_WAIT_MS;
|
||||
continue;
|
||||
} else {
|
||||
/* ret < 0: error */
|
||||
if (errno == EINTR) {
|
||||
continue; /* retry */
|
||||
}
|
||||
|
||||
/* for other errors, yield and retry (transient) */
|
||||
coop_wait(COOP_SYSCALLS_WAIT_MS);
|
||||
|
||||
if (timeout_ms > 0 && waited_ms >= timeout_ms) {
|
||||
return -1;
|
||||
}
|
||||
waited_ms += COOP_SYSCALLS_WAIT_MS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int __wrap_sleep(unsigned int seconds)
|
||||
{
|
||||
coop_wait(seconds * 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __wrap_usleep(useconds_t usec)
|
||||
{
|
||||
coop_wait((usec / 1000));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __wrap_socket(int domain, int type, int protocol)
|
||||
{
|
||||
int fd = __real_socket(domain, type, protocol);
|
||||
coop_set_fd_nonblocking(fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int __wrap_socketpair(int domain, int type, int protocol, int sv[2])
|
||||
{
|
||||
int ret = __real_socketpair(domain, type, protocol, sv);
|
||||
if (ret == 0) {
|
||||
coop_set_fd_nonblocking(sv[0]);
|
||||
coop_set_fd_nonblocking(sv[1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __wrap_pipe(int fds[2])
|
||||
{
|
||||
int ret = __real_pipe(fds);
|
||||
if (ret == 0) {
|
||||
coop_set_fd_nonblocking(fds[0]);
|
||||
coop_set_fd_nonblocking(fds[1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __wrap_pipe2(int fds[2], int flags)
|
||||
{
|
||||
int ret = __real_pipe2(fds, flags);
|
||||
if (ret == 0) {
|
||||
coop_set_fd_nonblocking(fds[0]);
|
||||
coop_set_fd_nonblocking(fds[1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __wrap_dup(int oldfd)
|
||||
{
|
||||
int fd = __real_dup(oldfd);
|
||||
coop_set_fd_nonblocking(fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int __wrap_dup2(int oldfd, int newfd)
|
||||
{
|
||||
int fd = __real_dup2(oldfd, newfd);
|
||||
coop_set_fd_nonblocking(fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int __wrap_open(const char *path, int flags, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int fd;
|
||||
|
||||
if (flags & O_CREAT) {
|
||||
va_start(ap, flags);
|
||||
mode_t mode = va_arg(ap, mode_t);
|
||||
va_end(ap);
|
||||
fd = __real_open(path, flags, mode);
|
||||
} else {
|
||||
fd = __real_open(path, flags);
|
||||
}
|
||||
coop_set_fd_nonblocking(fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
void linux_port_coop_syscalls_init(void)
|
||||
{
|
||||
coop_set_fd_nonblocking(STDIN_FILENO);
|
||||
coop_set_fd_nonblocking(STDOUT_FILENO);
|
||||
coop_set_fd_nonblocking(STDERR_FILENO);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Cooperative syscalls subsystem for the Linux FreeRTOS simulator.
|
||||
*
|
||||
* This header exposes the public initialization API needed by the
|
||||
* FreeRTOS Linux port. The subsystem provides blocking read()/write()
|
||||
* for FreeRTOS tasks without stalling the cooperative scheduler by
|
||||
* forwarding operations to a dedicated I/O worker thread.
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void linux_port_coop_syscalls_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct thread *thread_hdl;
|
||||
|
||||
void linux_port_setup_backtrace_signal(void);
|
||||
void linux_port_print_backtrace(void);
|
||||
pthread_t linux_port_get_scheduled_task_pthread(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,110 +1,94 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Amazon.com, Inc. or its affiliates
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.4.6
|
||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "wait_for_event.h"
|
||||
|
||||
struct event
|
||||
/*-----------------------------------------------------------*/
|
||||
/* Create a new event */
|
||||
event_t *event_create(void)
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
bool event_triggered;
|
||||
};
|
||||
|
||||
struct event * event_create(void)
|
||||
{
|
||||
struct event * ev = malloc( sizeof( struct event ) );
|
||||
event_t * ev = malloc(sizeof(event_t));
|
||||
assert(ev != NULL);
|
||||
|
||||
ev->event_triggered = false;
|
||||
pthread_mutex_init( &ev->mutex, NULL );
|
||||
pthread_cond_init( &ev->cond, NULL );
|
||||
pthread_mutex_init(&ev->mutex, NULL);
|
||||
pthread_cond_init(&ev->cond, NULL);
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
void event_delete( struct event * ev )
|
||||
/*-----------------------------------------------------------*/
|
||||
/* Delete an event */
|
||||
void event_delete(event_t *ev)
|
||||
{
|
||||
pthread_mutex_destroy( &ev->mutex );
|
||||
pthread_cond_destroy( &ev->cond );
|
||||
free( ev );
|
||||
pthread_mutex_destroy(&ev->mutex);
|
||||
pthread_cond_destroy(&ev->cond);
|
||||
free(ev);
|
||||
}
|
||||
|
||||
bool event_wait( struct event * ev )
|
||||
/*-----------------------------------------------------------*/
|
||||
/* Wait for event indefinitely (cooperative blocking) */
|
||||
bool event_wait(event_t *ev)
|
||||
{
|
||||
pthread_mutex_lock( &ev->mutex );
|
||||
pthread_mutex_lock(&ev->mutex);
|
||||
|
||||
while( ev->event_triggered == false )
|
||||
while (!ev->event_triggered)
|
||||
{
|
||||
pthread_cond_wait( &ev->cond, &ev->mutex );
|
||||
pthread_cond_wait(&ev->cond, &ev->mutex);
|
||||
}
|
||||
|
||||
ev->event_triggered = false;
|
||||
pthread_mutex_unlock( &ev->mutex );
|
||||
pthread_mutex_unlock(&ev->mutex);
|
||||
return true;
|
||||
}
|
||||
bool event_wait_timed( struct event * ev,
|
||||
time_t ms )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
/* Wait for event with timeout (milliseconds) */
|
||||
bool event_wait_timed(event_t *ev, time_t ms)
|
||||
{
|
||||
struct timespec ts;
|
||||
int ret = 0;
|
||||
|
||||
clock_gettime( CLOCK_REALTIME, &ts );
|
||||
ts.tv_sec += ms / 1000;
|
||||
ts.tv_nsec += ((ms % 1000) * 1000000);
|
||||
pthread_mutex_lock( &ev->mutex );
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += ms / 1000;
|
||||
ts.tv_nsec += (ms % 1000) * 1000000;
|
||||
|
||||
while( (ev->event_triggered == false) && (ret == 0) )
|
||||
/* Normalize tv_nsec in case it exceeds 1,000,000,000 */
|
||||
if (ts.tv_nsec >= 1000000000L) {
|
||||
ts.tv_sec += ts.tv_nsec / 1000000000L;
|
||||
ts.tv_nsec = ts.tv_nsec % 1000000000L;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ev->mutex);
|
||||
|
||||
while (!ev->event_triggered && ret == 0)
|
||||
{
|
||||
ret = pthread_cond_timedwait( &ev->cond, &ev->mutex, &ts );
|
||||
|
||||
if( ( ret == -1 ) && ( errno == ETIMEDOUT ) )
|
||||
ret = pthread_cond_timedwait(&ev->cond, &ev->mutex, &ts);
|
||||
if (ret == ETIMEDOUT)
|
||||
{
|
||||
ev->event_triggered = false;
|
||||
pthread_mutex_unlock(&ev->mutex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ev->event_triggered = false;
|
||||
pthread_mutex_unlock( &ev->mutex );
|
||||
pthread_mutex_unlock(&ev->mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void event_signal( struct event * ev )
|
||||
/*-----------------------------------------------------------*/
|
||||
/* Signal / resume an event */
|
||||
void event_signal(event_t *ev)
|
||||
{
|
||||
pthread_mutex_lock( &ev->mutex );
|
||||
pthread_mutex_lock(&ev->mutex);
|
||||
ev->event_triggered = true;
|
||||
pthread_cond_signal( &ev->cond );
|
||||
pthread_mutex_unlock( &ev->mutex );
|
||||
pthread_cond_signal(&ev->cond);
|
||||
pthread_mutex_unlock(&ev->mutex);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Amazon.com, Inc. or its affiliates
|
||||
* SPDX-FileCopyrightText: 2021-2025 Amazon.com, Inc. or its affiliates
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -31,21 +31,67 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _WAIT_FOR_EVENT_H_
|
||||
#define _WAIT_FOR_EVENT_H_
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
struct event;
|
||||
|
||||
struct event * event_create(void);
|
||||
void event_delete( struct event * );
|
||||
bool event_wait( struct event * ev );
|
||||
bool event_wait_timed( struct event * ev,
|
||||
time_t ms );
|
||||
void event_signal( struct event * ev );
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
typedef struct event
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
bool event_triggered;
|
||||
} event_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return event_t*
|
||||
*/
|
||||
event_t *event_create(void);
|
||||
|
||||
#endif /* ifndef _WAIT_FOR_EVENT_H_ */
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ev
|
||||
*/
|
||||
void event_delete(event_t *ev);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ev
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool event_wait(event_t *ev);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ev
|
||||
* @param ms
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool event_wait_timed(event_t *ev, time_t ms);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ev
|
||||
*/
|
||||
void event_signal(event_t *ev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user