diff --git a/src/fork-result.h b/src/fork-result.h
new file mode 100644
index 000000000..0f47f43a3
--- /dev/null
+++ b/src/fork-result.h
@@ -0,0 +1,33 @@
+// Copyright Cartesi and individual authors (see AUTHORS)
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with this program (see COPYING). If not, see .
+//
+
+#ifndef FORK_RESULT_H
+#define FORK_RESULT_H
+
+#include
+#include
+
+namespace cartesi {
+
+/// Result of a fork
+struct fork_result final {
+ std::string address;
+ uint32_t pid{};
+};
+
+} // namespace cartesi
+
+#endif
diff --git a/src/json-util.cpp b/src/json-util.cpp
index be8ac9044..55177b9f9 100644
--- a/src/json-util.cpp
+++ b/src/json-util.cpp
@@ -31,10 +31,10 @@
#include "access-log.h"
#include "base64.h"
#include "bracket-note.h"
+#include "fork-result.h"
#include "interpret.h"
#include "json-util.h"
#include "json.hpp"
-#include "jsonrpc-connection.h"
#include "machine-config.h"
#include "machine-memory-range-descr.h"
#include "machine-merkle-tree.h"
diff --git a/src/json-util.h b/src/json-util.h
index a5d8429a2..73c0cbf41 100644
--- a/src/json-util.h
+++ b/src/json-util.h
@@ -29,8 +29,8 @@
#include "access-log.h"
#include "bracket-note.h"
+#include "fork-result.h"
#include "interpret.h"
-#include "jsonrpc-connection.h"
#include "machine-config.h"
#include "machine-memory-range-descr.h"
#include "machine-merkle-tree.h"
diff --git a/src/jsonrpc-connection.h b/src/jsonrpc-connection.h
index 0d5dc6d1c..2f48063d6 100644
--- a/src/jsonrpc-connection.h
+++ b/src/jsonrpc-connection.h
@@ -27,16 +27,11 @@
#include
#pragma GCC diagnostic pop
+#include "fork-result.h"
#include "semantic-version.h"
namespace cartesi {
-/// Result of a fork
-struct fork_result final {
- std::string address;
- uint32_t pid{};
-};
-
class jsonrpc_connection final {
public:
jsonrpc_connection(std::string remote_address, bool detach_server);
diff --git a/src/jsonrpc-machine-c-api.cpp b/src/jsonrpc-machine-c-api.cpp
index 069ffd4ed..b35a059ce 100644
--- a/src/jsonrpc-machine-c-api.cpp
+++ b/src/jsonrpc-machine-c-api.cpp
@@ -89,6 +89,7 @@ cm_error cm_jsonrpc_connect(const char *address, int detach_server, cm_jsonrpc_c
return cm_result_failure();
}
+#ifdef HAVE_FORK
static boost::asio::ip::tcp::endpoint address_to_endpoint(const std::string &address) {
try {
const auto pos = address.find_last_of(':');
@@ -108,6 +109,7 @@ static std::string endpoint_to_string(const boost::asio::ip::tcp::endpoint &endp
ss << endpoint;
return ss.str();
}
+#endif
cm_error cm_jsonrpc_spawn_server(const char *address, int detach_server, cm_jsonrpc_connection **con,
const char **bound_address, int32_t *pid) try {
@@ -131,6 +133,7 @@ cm_error cm_jsonrpc_spawn_server(const char *address, int detach_server, cm_json
if (pid == nullptr) {
throw std::invalid_argument("invalid pid output");
}
+#ifdef HAVE_FORK
sigset_t mask{};
sigset_t omask{};
sigemptyset(&mask); // always returns 0
@@ -239,6 +242,10 @@ cm_error cm_jsonrpc_spawn_server(const char *address, int detach_server, cm_json
}
}
return cm_result_success(); // code never reaches here
+#else
+ throw std::runtime_error{"spawn is unsupported in this platform"};
+
+#endif
} catch (...) {
*con = nullptr;
*bound_address = nullptr;
diff --git a/src/jsonrpc-remote-machine.cpp b/src/jsonrpc-remote-machine.cpp
index 3d4ce60ff..835ae9079 100644
--- a/src/jsonrpc-remote-machine.cpp
+++ b/src/jsonrpc-remote-machine.cpp
@@ -54,6 +54,7 @@
#include "access-log.h"
#include "base64.h"
+#include "fork-result.h"
#include "interpret.h"
#include "json-util.h"
#include "jsonrpc-connection.h"
diff --git a/src/jsonrpc-virtual-machine.cpp b/src/jsonrpc-virtual-machine.cpp
index 05101d02d..c6c505f71 100644
--- a/src/jsonrpc-virtual-machine.cpp
+++ b/src/jsonrpc-virtual-machine.cpp
@@ -37,6 +37,7 @@
#include "access-log.h"
#include "base64.h"
+#include "fork-result.h"
#include "interpret.h"
#include "json-util.h"
#include "json.hpp"
diff --git a/src/os-features.h b/src/os-features.h
index 6daf54827..42b591f1d 100644
--- a/src/os-features.h
+++ b/src/os-features.h
@@ -68,4 +68,8 @@
#define HAVE_USLEEP
#endif
+#if !defined(NO_FORK) && (defined(__linux__) || defined(__unix__))
+#define HAVE_FORK
+#endif
+
#endif
diff --git a/src/os.cpp b/src/os.cpp
index ad15da20c..af98d5255 100644
--- a/src/os.cpp
+++ b/src/os.cpp
@@ -34,7 +34,6 @@
#include "unique-c-ptr.h"
#include
-#include
#ifdef HAVE_SIGACTION
#include
@@ -92,14 +91,18 @@
#else // not _WIN32
-#if defined(HAVE_TTY) || defined(HAVE_MMAP) || defined(HAVE_TERMIOS) || defined(HAVE_USLEEP)
-#include // write/read/close
+#if defined(HAVE_TTY) || defined(HAVE_MMAP) || defined(HAVE_TERMIOS) || defined(HAVE_USLEEP) || defined(HAVE_FORK)
+#include // write/read/close/usleep/fork
#endif
#if defined(HAVE_SELECT)
#include // select
#endif
+#if defined(HAVE_FORK)
+#include
+#endif
+
#define plat_write write
#define plat_mkdir mkdir
@@ -383,7 +386,7 @@ void os_prepare_tty_select([[maybe_unused]] select_fd_sets *fds) {
#endif
}
-bool os_poll_selected_tty(int select_ret, select_fd_sets *fds) {
+bool os_poll_selected_tty([[maybe_unused]] int select_ret, [[maybe_unused]] select_fd_sets *fds) {
auto *s = get_state();
if (!s->initialized) { // We can't poll when TTY is not initialized
return false;
@@ -522,7 +525,7 @@ void os_putchars(const uint8_t *data, size_t len) {
}
}
-int os_mkdir(const char *path, int mode) {
+int os_mkdir([[maybe_unused]] const char *path, [[maybe_unused]] int mode) {
#ifdef HAVE_MKDIR
return plat_mkdir(path, mode);
#else
@@ -781,9 +784,11 @@ void os_sleep_us(uint64_t timeout_us) {
#endif
}
+#ifdef HAVE_FORK
static void sig_alrm(int /*unused*/) {
;
}
+#endif
// this function forks and intermediate child, and the intermediate child forks a final child
// the intermediate child simply exits immediately
@@ -791,7 +796,8 @@ static void sig_alrm(int /*unused*/) {
// the parent returns the final child pid
// the final child returns 0
// on error, the parent throws and the final child does not return
-int os_double_fork_or_throw(int newpgid) {
+int os_double_fork_or_throw([[maybe_unused]] int newpgid) {
+#ifdef HAVE_FORK
int fd[2] = {-1, -1};
struct sigaction chld_act {};
bool restore_sigchld = false;
@@ -926,9 +932,15 @@ int os_double_fork_or_throw(int newpgid) {
}
throw; // rethrow so caller can see why we failed
}
+
+#else
+ throw std::runtime_error{"fork() is unsupported in this platform"s};
+
+#endif
}
-int os_double_fork(int newpgid, const char **err_msg) {
+int os_double_fork([[maybe_unused]] int newpgid, [[maybe_unused]] const char **err_msg) {
+#ifdef HAVE_FORK
static THREAD_LOCAL std::string error_storage;
try {
*err_msg = nullptr;
@@ -938,6 +950,10 @@ int os_double_fork(int newpgid, const char **err_msg) {
*err_msg = error_storage.c_str();
return -1;
}
+#else
+ throw std::runtime_error{"fork() is unsupported in this platform"s};
+
+#endif
}
} // namespace cartesi