Avoid exceptions
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
#include "connection_registry.hpp"
|
||||
#include "connection.hpp"
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <unistd.h>
|
||||
|
||||
ConnectionRegistry::ConnectionRegistry() : connections_(nullptr), max_fds_(0) {
|
||||
// Get the process file descriptor limit
|
||||
struct rlimit rlim;
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) {
|
||||
throw std::runtime_error("Failed to get RLIMIT_NOFILE");
|
||||
perror("getrlimit");
|
||||
std::abort();
|
||||
}
|
||||
max_fds_ = rlim.rlim_cur;
|
||||
|
||||
@@ -25,7 +26,8 @@ ConnectionRegistry::ConnectionRegistry() : connections_(nullptr), max_fds_(0) {
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
|
||||
if (connections_ == MAP_FAILED) {
|
||||
throw std::runtime_error("Failed to mmap for connection registry");
|
||||
perror("mmap");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// Store aligned size for munmap
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
* Initialize the connection registry.
|
||||
* Allocates virtual address space based on RLIMIT_NOFILE.
|
||||
*
|
||||
* @throws std::runtime_error if mmap fails or RLIMIT_NOFILE cannot be read
|
||||
* Aborts the process if mmap fails or RLIMIT_NOFILE cannot be read
|
||||
*/
|
||||
ConnectionRegistry();
|
||||
|
||||
|
||||
24
src/main.cpp
24
src/main.cpp
@@ -37,7 +37,7 @@ std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
|
||||
int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sfd == -1) {
|
||||
perror("socket");
|
||||
throw std::runtime_error("Failed to create unix socket");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// Remove existing socket file if it exists
|
||||
@@ -49,7 +49,8 @@ std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
|
||||
|
||||
if (config.server.unix_socket_path.length() >= sizeof(addr.sun_path)) {
|
||||
close(sfd);
|
||||
throw std::runtime_error("Unix socket path too long");
|
||||
std::fprintf(stderr, "Unix socket path too long\n");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
strncpy(addr.sun_path, config.server.unix_socket_path.c_str(),
|
||||
@@ -58,13 +59,13 @@ std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
|
||||
if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
perror("bind");
|
||||
close(sfd);
|
||||
throw std::runtime_error("Failed to bind unix socket");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (listen(sfd, SOMAXCONN) == -1) {
|
||||
perror("listen");
|
||||
close(sfd);
|
||||
throw std::runtime_error("Failed to listen on unix socket");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
listen_fds.push_back(sfd);
|
||||
@@ -89,7 +90,7 @@ std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
|
||||
std::to_string(config.server.port).c_str(), &hints, &result);
|
||||
if (s != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
|
||||
throw std::runtime_error("Failed to resolve bind address");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
int sfd = -1;
|
||||
@@ -126,13 +127,14 @@ std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
|
||||
freeaddrinfo(result);
|
||||
|
||||
if (rp == nullptr || sfd == -1) {
|
||||
throw std::runtime_error("Could not bind to any address");
|
||||
std::fprintf(stderr, "Could not bind to any address\n");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (listen(sfd, SOMAXCONN) == -1) {
|
||||
perror("listen");
|
||||
close(sfd);
|
||||
throw std::runtime_error("Failed to listen on socket");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
listen_fds.push_back(sfd);
|
||||
@@ -236,13 +238,7 @@ int main(int argc, char *argv[]) {
|
||||
<< std::endl;
|
||||
|
||||
// Create listen sockets
|
||||
std::vector<int> listen_fds;
|
||||
try {
|
||||
listen_fds = create_listen_sockets(*config);
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Failed to create listen sockets: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::vector<int> listen_fds = create_listen_sockets(*config);
|
||||
|
||||
// Create handler and server
|
||||
HttpHandler http_handler;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <pthread.h>
|
||||
#include <stdexcept>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -39,12 +38,12 @@ Server::Server(const weaseldb::Config &config, ConnectionHandler &handler,
|
||||
for (int fd : listen_fds_) {
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags == -1) {
|
||||
perror("fcntl F_GETFL on provided listen fd");
|
||||
throw std::runtime_error("Failed to get flags for provided listen fd");
|
||||
perror("fcntl F_GETFL");
|
||||
std::abort();
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
perror("fcntl F_SETFL O_NONBLOCK on provided listen fd");
|
||||
throw std::runtime_error("Failed to set provided listen fd non-blocking");
|
||||
perror("fcntl F_SETFL O_NONBLOCK");
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,14 +178,14 @@ int Server::createLocalConnection() {
|
||||
|
||||
int flags = fcntl(server_fd, F_GETFL, 0);
|
||||
if (flags == -1) {
|
||||
perror("fcntl F_GETFL on provided listen fd");
|
||||
throw std::runtime_error(
|
||||
"Failed to get flags for server side of local connection");
|
||||
std::fprintf(stderr,
|
||||
"Server::createLocalConnection: fcntl F_GETFL failed\n");
|
||||
std::abort();
|
||||
}
|
||||
if (fcntl(server_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
perror("fcntl F_SETFL O_NONBLOCK on provided listen fd");
|
||||
throw std::runtime_error(
|
||||
"Failed to set server side of local connection to non-blocking");
|
||||
std::fprintf(stderr,
|
||||
"Server::createLocalConnection: fcntl F_SETFL failed\n");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// Create sockaddr_storage for the connection
|
||||
@@ -226,14 +225,14 @@ int Server::createLocalConnection() {
|
||||
void Server::setup_shutdown_pipe() {
|
||||
if (pipe(shutdown_pipe_) == -1) {
|
||||
perror("pipe");
|
||||
throw std::runtime_error("Failed to create shutdown pipe");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// Set both ends to close-on-exec
|
||||
if (fcntl(shutdown_pipe_[0], F_SETFD, FD_CLOEXEC) == -1 ||
|
||||
fcntl(shutdown_pipe_[1], F_SETFD, FD_CLOEXEC) == -1) {
|
||||
perror("fcntl FD_CLOEXEC");
|
||||
throw std::runtime_error("Failed to set close-on-exec for shutdown pipe");
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,8 +243,8 @@ void Server::create_epoll_instances() {
|
||||
for (int i = 0; i < config_.server.epoll_instances; ++i) {
|
||||
epoll_fds_[i] = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (epoll_fds_[i] == -1) {
|
||||
perror("epoll_create");
|
||||
throw std::runtime_error("Failed to create epoll instance");
|
||||
perror("epoll_create1");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// Add shutdown pipe to each epoll instance
|
||||
@@ -256,7 +255,7 @@ void Server::create_epoll_instances() {
|
||||
if (epoll_ctl(epoll_fds_[i], EPOLL_CTL_ADD, shutdown_pipe_[0],
|
||||
&shutdown_event) == -1) {
|
||||
perror("epoll_ctl shutdown pipe");
|
||||
throw std::runtime_error("Failed to add shutdown pipe to epoll");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// Add all listen sockets to each epoll instance with EPOLLEXCLUSIVE to
|
||||
@@ -268,7 +267,7 @@ void Server::create_epoll_instances() {
|
||||
if (epoll_ctl(epoll_fds_[i], EPOLL_CTL_ADD, listen_fd, &listen_event) ==
|
||||
-1) {
|
||||
perror("epoll_ctl listen socket");
|
||||
throw std::runtime_error("Failed to add listen socket to epoll");
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ struct Server : std::enable_shared_from_this<Server> {
|
||||
* - Starts all worker threads
|
||||
* - Blocks until shutdown() is called or an error occurs
|
||||
*
|
||||
* @throws std::runtime_error on socket creation or configuration errors
|
||||
* Aborts the process on socket creation or configuration errors
|
||||
*/
|
||||
void run();
|
||||
|
||||
|
||||
13
style.md
13
style.md
@@ -301,8 +301,7 @@ arena.reset(); // Reset arena memory
|
||||
|
||||
### Error Reporting
|
||||
- **Return codes** for expected errors
|
||||
- **Exceptions** only for exceptional circumstances
|
||||
- **fprintf + abort()** for unrecoverable errors
|
||||
- **Avoid exceptions** - If we can't uphold the component's contract, perror/fprintf then abort. If we want to try to recover, change the component's contract to allow returning an error code.
|
||||
- **Error messages are for humans only** - never parse error message strings programmatically
|
||||
- **Error codes are the contract** - use enums/codes for programmatic error handling
|
||||
```cpp
|
||||
@@ -317,9 +316,13 @@ if (result == ParseResult::InvalidJson) {
|
||||
// Bad: Don't test or parse error message strings
|
||||
// CHECK(parser.get_error() == "Expected '}' at line 5"); // BRITTLE!
|
||||
|
||||
if (!memory) {
|
||||
std::fprintf(stderr, "ArenaAllocator: Failed to allocate memory\n");
|
||||
std::abort();
|
||||
// System resource failures: abort immediately
|
||||
void ArenaAllocator::allocate() {
|
||||
void* memory = malloc(size);
|
||||
if (!memory) {
|
||||
perror("malloc");
|
||||
std::abort(); // Process is likely in bad state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user