Skip to content

Commit c631fe2

Browse files
committed
Fix MacOS build
1 parent 14bc2d0 commit c631fe2

File tree

2 files changed

+100
-7
lines changed

2 files changed

+100
-7
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
- Change include folder structure from include/slick_socket/ to include/slick/
33
- Change namespace from slick_socket to slick::socket
44
- Add GitHub CI workflow
5+
- Fix MacOS build by using kqueue/kevent
56

67
#1.0.0.0 - [09/26/2025]
78
- Initial Release

include/slick/socket/tcp_server_unix.h

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313
#include <algorithm>
1414
#include <cstring>
1515
#include <pthread.h>
16+
17+
#ifdef __APPLE__
18+
#include <sys/event.h>
19+
#include <sys/time.h>
20+
#else
1621
#include <sys/epoll.h>
22+
#endif
1723

1824
namespace slick::socket
1925
{
@@ -204,7 +210,13 @@ inline bool TCPServerBase<DerivedT>::send_data(int client_id, const std::vector<
204210
template<typename DerivedT>
205211
inline void TCPServerBase<DerivedT>::close_socket(SocketT socket)
206212
{
213+
#ifdef __APPLE__
214+
struct kevent ev;
215+
EV_SET(&ev, socket, EVFILT_READ, EV_DELETE, 0, 0, 0);
216+
kevent(epoll_fd_, &ev, 1, nullptr, 0, nullptr);
217+
#else
207218
epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, socket, nullptr);
219+
#endif
208220
socket_to_client_id_.erase(socket);
209221
close(socket);
210222
}
@@ -226,24 +238,92 @@ void TCPServerBase<DerivedT>::server_loop()
226238
// Set CPU affinity if specified
227239
if (config_.cpu_affinity >= 0)
228240
{
241+
#ifndef __APPLE__
229242
cpu_set_t cpuset;
230243
CPU_ZERO(&cpuset);
231244
CPU_SET(config_.cpu_affinity, &cpuset);
232-
245+
233246
pthread_t thread = pthread_self();
234247
int result = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
235248
if (result != 0)
236249
{
237-
LOG_WARN("Failed to set CPU affinity to core {}: {}",
250+
LOG_WARN("Failed to set CPU affinity to core {}: {}",
238251
config_.cpu_affinity, std::strerror(result));
239252
}
240253
else
241254
{
242255
LOG_INFO("Server thread pinned to CPU core {}", config_.cpu_affinity);
243256
}
257+
#else
258+
LOG_WARN("CPU affinity not supported on macOS");
259+
#endif
260+
}
261+
262+
#ifdef __APPLE__
263+
// macOS: Use kqueue
264+
epoll_fd_ = kqueue();
265+
if (epoll_fd_ < 0)
266+
{
267+
LOG_ERROR("Failed to create kqueue instance: {}", std::strerror(errno));
268+
return;
269+
}
270+
271+
// Add server socket to kqueue
272+
struct kevent ev;
273+
EV_SET(&ev, server_socket_, EVFILT_READ, EV_ADD, 0, 0, 0);
274+
if (kevent(epoll_fd_, &ev, 1, nullptr, 0, nullptr) < 0)
275+
{
276+
LOG_ERROR("Failed to add server socket to kqueue: {}", std::strerror(errno));
277+
close(epoll_fd_);
278+
epoll_fd_ = -1;
279+
return;
280+
}
281+
282+
const int MAX_EVENTS = 64;
283+
struct kevent events[MAX_EVENTS];
284+
std::vector<uint8_t> buffer(config_.receive_buffer_size);
285+
286+
while (running_.load())
287+
{
288+
// Wait for events with 1 second timeout
289+
int num_events = kevent(epoll_fd_, nullptr, 0, events, MAX_EVENTS, nullptr);
290+
if (num_events < 0)
291+
{
292+
if (errno == EINTR)
293+
{
294+
continue;
295+
}
296+
LOG_ERROR("kevent failed: {}", std::strerror(errno));
297+
break;
298+
}
299+
300+
for (int i = 0; i < num_events; i++)
301+
{
302+
int fd = static_cast<int>(events[i].ident);
303+
if (fd == server_socket_)
304+
{
305+
// New connection on server socket
306+
accept_new_client();
307+
}
308+
else
309+
{
310+
auto it = socket_to_client_id_.find(fd);
311+
if (it != socket_to_client_id_.end())
312+
{
313+
handle_client_data(it->second, buffer);
314+
}
315+
}
316+
}
244317
}
245318

246-
// Create epoll instance
319+
// Clean up
320+
if (epoll_fd_ >= 0)
321+
{
322+
close(epoll_fd_);
323+
epoll_fd_ = -1;
324+
}
325+
#else
326+
// Linux: Use epoll
247327
epoll_fd_ = epoll_create1(0);
248328
if (epoll_fd_ < 0)
249329
{
@@ -300,11 +380,12 @@ void TCPServerBase<DerivedT>::server_loop()
300380
}
301381

302382
// Clean up
303-
if (epoll_fd_ != nullptr)
383+
if (epoll_fd_ >= 0)
304384
{
305-
epoll_close(epoll_fd_);
306-
epoll_fd_ = nullptr;
385+
close(epoll_fd_);
386+
epoll_fd_ = -1;
307387
}
388+
#endif
308389
}
309390

310391
template<typename DerivedT>
@@ -330,7 +411,17 @@ void TCPServerBase<DerivedT>::accept_new_client()
330411
fcntl(client_socket, F_SETFL, flags | O_NONBLOCK);
331412
}
332413

333-
// Add client socket to epoll
414+
// Add client socket to event system
415+
#ifdef __APPLE__
416+
struct kevent ev;
417+
EV_SET(&ev, client_socket, EVFILT_READ, EV_ADD, 0, 0, 0);
418+
if (kevent(epoll_fd_, &ev, 1, nullptr, 0, nullptr) < 0)
419+
{
420+
LOG_ERROR("Failed to add client socket to kqueue: {}", std::strerror(errno));
421+
close(client_socket);
422+
return;
423+
}
424+
#else
334425
struct epoll_event ev;
335426
ev.events = EPOLLIN | EPOLLET; // Edge-triggered mode
336427
ev.data.fd = client_socket;
@@ -340,6 +431,7 @@ void TCPServerBase<DerivedT>::accept_new_client()
340431
close(client_socket);
341432
return;
342433
}
434+
#endif
343435

344436
// Get client address
345437
char addr_str[INET_ADDRSTRLEN];

0 commit comments

Comments
 (0)