libxev is a cross-platform, high-performance event loop that provides abstractions for non-blocking IO, timers, events, and more and works on Linux (io_uring or epoll), macOS (kqueue), and Wasm + WASI. Available as both a Zig and C API.
Nice hard work (for you and all your collaborators) to make this library.
I have been playing with the xev api for C code on linux today.
However, some trouble was encountered when running the same code with or without xev.
Client: curl 127.0.0.1:8000.
Without xev
C code - server
```c
#include
#include
#include
#include
#include
#include
#include
#define PORT 8000 // The port number for the server to listen on
int main() {
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
// Create a socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("Socket creation failed");
exit(1);
}
// Bind the socket to an IP address and port
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; // Listen on all available network interfaces
server_addr.sin_port = htons(PORT);
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("Socket binding failed");
close(server_socket);
exit(1);
}
// Listen for incoming connections
if (listen(server_socket, 10) == -1) {
perror("Listen failed");
close(server_socket);
exit(1);
}
printf("Server listening on port %d...\n", PORT);
while (1) {
// Accept a client connection
client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);
if (client_socket == -1) {
perror("Accept failed");
continue; // Continue listening for other connections
}
printf("Connection accepted from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// Handle the client connection (in this example, we simply echo back received data)
char buffer[1024];
ssize_t bytes_received;
while ((bytes_received = recv(client_socket, buffer, sizeof(buffer), 0)) > 0) {
buffer[bytes_received] = '\0'; // Null-terminate the received data
printf("Received: %s", buffer);
// Echo back to the client
send(client_socket, buffer, bytes_received, 0);
}
// Close the client socket
close(client_socket);
printf("Connection closed by %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
}
// Close the server socket (this part will not be reached in this example)
close(server_socket);
return 0;
}
```
Output
$> ./server_example
Server listening on port 8000...
Connection accepted from 127.0.0.1:42220
Received: GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: curl/8.2.1
Accept: */*
Connection closed by 127.0.0.1:42220
With xev
C code - server
```c
#include "xev.h"
#include
#include
#include
#include
#include
#include
#define PORT 8000 // The port number for the server to listen on
void on_connection(xev_loop* loop, xev_completion* c, int result, void* userdata) {
int server_socket = *(int*)userdata;
int client_socket = accept(server_socket, NULL, NULL);
if (client_socket == -1) {
perror("Accept failed");
return;
}
char buffer[1024];
ssize_t bytes_received;
while ((bytes_received = recv(client_socket, buffer, sizeof(buffer), 0)) > 0) {
buffer[bytes_received] = '\0'; // Null-terminate the received data
printf("Received: %s", buffer);
// Echo back to the client
send(client_socket, buffer, bytes_received, 0);
}
close(client_socket);
}
int main() {
xev_loop loop;
if (xev_loop_init(&loop) != 0) {
fprintf(stderr, "Failed to initialize event loop\n");
return 1;
}
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
// Create a socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("Socket creation failed");
exit(1);
}
// Bind the socket to an IP address and port
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; // Listen on all available network interfaces
server_addr.sin_port = htons(PORT);
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("Socket binding failed");
close(server_socket);
exit(1);
}
// Listen for incoming connections
if (listen(server_socket, 10) == -1) {
perror("Listen failed");
close(server_socket);
exit(1);
}
printf("Server listening on port %d...\n", PORT);
// Pass the server_socket as user data to the connection handler
int user_data = server_socket;
xev_completion completion;
xev_completion_zero(&completion);
xev_threadpool_task task;
xev_threadpool_task_init(&task, (xev_task_cb)on_connection);
xev_threadpool_batch batch;
xev_threadpool_batch_init(&batch);
xev_threadpool_batch_push_task(&batch, &task);
xev_threadpool threadpool;
xev_threadpool_init(&threadpool, NULL);
xev_threadpool_schedule(&threadpool, &batch);
xev_threadpool_deinit(&threadpool);
xev_loop_run(&loop, XEV_RUN_UNTIL_DONE);
xev_loop_deinit(&loop);
close(server_socket);
return 0;
}
```
Output
$> ./server_example
Server listening on port 8000...
Accept failed: Bad file descriptor
Thanks, the C API is admittedly anemic right now and not well maintained beyond extremely basic tested usage. I'm sure there are many improvements to be made here.
Hi @mitchellh,
Nice hard work (for you and all your collaborators) to make this library.
I have been playing with the xev api for C code on linux today. However, some trouble was encountered when running the same code with or without xev.
Client:
curl 127.0.0.1:8000
.Without
xev
C code - server
```c #includeOutput
With
xev
C code - server
```c #include "xev.h" #includeOutput
hold client, needed Ctrl+C to stopping.
Note:
gcc
get errors ondata
array on header.