mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-17 02:45:05 +00:00
193 lines
5.3 KiB
C++
193 lines
5.3 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Symbols resolved for ELF apps ahead of every other module's (see app_esp32_symbol_resolver()).
|
|
// Firmware code calling the same functions never gets here.
|
|
// Pending signals are delivered here, at the entry and again when a call was interrupted by one,
|
|
// since the app holds no lock of the system itself there.
|
|
// Allocations are counted per app instance (see app/memory.h).
|
|
#include <app/libc.h>
|
|
#include <app/memory.h>
|
|
#include <app/signal.h>
|
|
|
|
#include <esp_heap_caps.h>
|
|
|
|
#include <tactility/module.h>
|
|
|
|
#include <sys/poll.h>
|
|
#include <unistd.h>
|
|
|
|
#include <cerrno>
|
|
#include <csignal>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <new>
|
|
|
|
namespace {
|
|
|
|
ssize_t app_read(int fd, void* buffer, size_t size) {
|
|
app_signal_deliver_pending();
|
|
const ssize_t result = read(fd, buffer, size);
|
|
if (result < 0 && errno == EINTR) {
|
|
app_signal_deliver_pending();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ssize_t app_write(int fd, const void* buffer, size_t size) {
|
|
app_signal_deliver_pending();
|
|
const ssize_t result = write(fd, buffer, size);
|
|
if (result < 0 && errno == EINTR) {
|
|
app_signal_deliver_pending();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int app_poll(struct pollfd* fds, nfds_t nfds, int timeout) {
|
|
app_signal_deliver_pending();
|
|
const int result = poll(fds, nfds, timeout);
|
|
if (result < 0 && errno == EINTR) {
|
|
app_signal_deliver_pending();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int app_usleep(useconds_t usec) {
|
|
app_signal_deliver_pending();
|
|
int result;
|
|
if (!app_libc_try_usleep(usec, &result)) {
|
|
return usleep(usec);
|
|
}
|
|
app_signal_deliver_pending();
|
|
return result;
|
|
}
|
|
|
|
unsigned int app_sleep(unsigned int seconds) {
|
|
app_signal_deliver_pending();
|
|
unsigned int result;
|
|
if (!app_libc_try_sleep(seconds, &result)) {
|
|
return sleep(seconds);
|
|
}
|
|
app_signal_deliver_pending();
|
|
return result;
|
|
}
|
|
|
|
int app_kill(pid_t pid, int sig) {
|
|
const int result = kill(pid, sig);
|
|
// A signal sent to the app itself is delivered before kill() returns
|
|
app_signal_deliver_pending();
|
|
return result;
|
|
}
|
|
|
|
pid_t app_getpid() {
|
|
int result;
|
|
return app_libc_try_getpid(&result) ? result : 0;
|
|
}
|
|
|
|
pid_t app_getppid() {
|
|
int result;
|
|
return app_libc_try_getppid(&result) ? result : 0;
|
|
}
|
|
|
|
void* record_alloc(void* ptr) {
|
|
if (ptr != nullptr) {
|
|
app_memory_record_alloc(heap_caps_get_allocated_size(ptr));
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
void record_free(void* ptr) {
|
|
if (ptr != nullptr) {
|
|
app_memory_record_free(heap_caps_get_allocated_size(ptr));
|
|
}
|
|
}
|
|
|
|
void* app_malloc(size_t size) {
|
|
return record_alloc(malloc(size));
|
|
}
|
|
|
|
void* app_calloc(size_t count, size_t size) {
|
|
return record_alloc(calloc(count, size));
|
|
}
|
|
|
|
void* app_realloc(void* ptr, size_t size) {
|
|
const size_t old_size = (ptr != nullptr) ? heap_caps_get_allocated_size(ptr) : 0;
|
|
void* result = realloc(ptr, size);
|
|
// A failed realloc() leaves the old block allocated
|
|
if (result != nullptr || size == 0) {
|
|
if (ptr != nullptr) {
|
|
app_memory_record_free(old_size);
|
|
}
|
|
record_alloc(result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void app_free(void* ptr) {
|
|
record_free(ptr);
|
|
free(ptr);
|
|
}
|
|
|
|
char* app_strdup(const char* s) {
|
|
return static_cast<char*>(record_alloc(strdup(s)));
|
|
}
|
|
|
|
char* app_strndup(const char* s, size_t n) {
|
|
return static_cast<char*>(record_alloc(strndup(s, n)));
|
|
}
|
|
|
|
void* app_operator_new(size_t size) {
|
|
return record_alloc(::operator new(size));
|
|
}
|
|
|
|
void* app_operator_new_array(size_t size) {
|
|
return record_alloc(::operator new[](size));
|
|
}
|
|
|
|
void app_operator_delete(void* ptr) {
|
|
record_free(ptr);
|
|
::operator delete(ptr);
|
|
}
|
|
|
|
void app_operator_delete_array(void* ptr) {
|
|
record_free(ptr);
|
|
::operator delete[](ptr);
|
|
}
|
|
|
|
void app_operator_delete_sized(void* ptr, size_t) {
|
|
app_operator_delete(ptr);
|
|
}
|
|
|
|
void app_operator_delete_array_sized(void* ptr, size_t) {
|
|
app_operator_delete_array(ptr);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
extern "C" {
|
|
|
|
extern const ModuleSymbol app_esp32_symbols[] = {
|
|
{ "read", reinterpret_cast<void*>(app_read) },
|
|
{ "write", reinterpret_cast<void*>(app_write) },
|
|
{ "poll", reinterpret_cast<void*>(app_poll) },
|
|
{ "usleep", reinterpret_cast<void*>(app_usleep) },
|
|
{ "sleep", reinterpret_cast<void*>(app_sleep) },
|
|
{ "kill", reinterpret_cast<void*>(app_kill) },
|
|
{ "getpid", reinterpret_cast<void*>(app_getpid) },
|
|
{ "getppid", reinterpret_cast<void*>(app_getppid) },
|
|
{ "malloc", reinterpret_cast<void*>(app_malloc) },
|
|
{ "calloc", reinterpret_cast<void*>(app_calloc) },
|
|
{ "realloc", reinterpret_cast<void*>(app_realloc) },
|
|
{ "free", reinterpret_cast<void*>(app_free) },
|
|
{ "strdup", reinterpret_cast<void*>(app_strdup) },
|
|
{ "strndup", reinterpret_cast<void*>(app_strndup) },
|
|
{ "_Znwj", reinterpret_cast<void*>(app_operator_new) }, // operator new(unsigned int)
|
|
{ "_Znaj", reinterpret_cast<void*>(app_operator_new_array) }, // operator new[](unsigned int)
|
|
{ "_ZdlPv", reinterpret_cast<void*>(app_operator_delete) }, // operator delete(void*)
|
|
{ "_ZdaPv", reinterpret_cast<void*>(app_operator_delete_array) }, // operator delete[](void*)
|
|
{ "_ZdlPvj", reinterpret_cast<void*>(app_operator_delete_sized) }, // operator delete(void*, unsigned int)
|
|
{ "_ZdaPvj", reinterpret_cast<void*>(app_operator_delete_array_sized) }, // operator delete[](void*, unsigned int)
|
|
MODULE_SYMBOL_TERMINATOR
|
|
};
|
|
|
|
}
|