cmogstored 1.8.1 - use default system stack size
[cmogstored.git] / accept_loop.c
blob1f327276cdbfa32474ad6ccad7f302a7fd80c87f
1 /*
2 * Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
3 * License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
4 */
5 #include "cmogstored.h"
6 #include "compat_accept.h"
8 #define ENOSYS_msg \
9 MOG_ACCEPT_FN" missing, rebuild on the same platform this runs on"
11 /* don't spam syslog on accept flood */
12 static void do_expire(struct mog_accept *ac)
14 int err = errno;
15 time_t now;
16 static time_t last_expire;
17 static pthread_mutex_t err_lock = PTHREAD_MUTEX_INITIALIZER;
19 CHECK(int, 0, pthread_mutex_lock(&err_lock));
21 now = time(NULL);
22 if (last_expire == now)
23 err = 0;
24 else
25 last_expire = now;
27 CHECK(int, 0, pthread_mutex_unlock(&err_lock));
29 if (err) {
30 errno = err;
31 syslog(LOG_ERR, MOG_ACCEPT_FN" failed with: %m");
34 mog_fdmap_expire(ac->svc->idle_timeout);
37 MOG_NOINLINE static void accept_error_check(struct mog_accept *ac)
39 int fd;
41 switch (errno) {
42 case ECONNABORTED:
43 /* common error, nothing we can do about it */
44 case EINTR:
45 /* we'll hit mog_thr_test_quit when we restart the loop */
46 return;
47 case EBADF:
48 assert(0 && "BUG, called accept on bad FD");
49 case ENOTSOCK:
50 case EOPNOTSUPP:
51 pthread_exit(NULL);
52 case_EAGAIN:
54 * listen socket could've been inherited from another process,
55 * we'll support that in the near future (like nginx/unicorn)
57 fd = mog_fd_of(ac)->fd;
58 if (mog_set_nonblocking(fd, false) != 0) {
59 assert(errno != EBADF && "unexpected EBADF");
60 syslog(LOG_ERR,
61 "failed to make fd=%d blocking: %m", fd);
63 syslog(LOG_DEBUG, "made fd=%d blocking", fd);
64 return;
65 case EMFILE:
66 case ENFILE:
67 case ENOBUFS:
68 case ENOMEM:
69 do_expire(ac);
70 return;
71 case ENOSYS:
72 syslog(LOG_CRIT, ENOSYS_msg);
73 die(ENOSYS_msg);
74 default:
75 syslog(LOG_ERR, MOG_ACCEPT_FN" failed with: %m");
80 * passed as the start_routine argument to pthread_create.
81 * This function may run concurrently in multiple threads.
82 * The design of cmogstored assumes "wake-one" behavior for blocking
83 * accept()/accept4() callers. We will force accept_fd into blocking
84 * state if O_NONBLOCK is ever set (e.g. listen socket was inherited).
86 void *mog_accept_loop(void *arg)
88 struct mog_accept *ac = arg;
89 int accept_fd = mog_fd_of(ac)->fd;
90 union mog_sockaddr msa;
92 for (;;) {
93 socklen_t salen = (socklen_t)sizeof(msa);
94 int client_fd;
96 mog_thr_test_quit();
97 client_fd = mog_accept_fn(accept_fd, &msa.sa, &salen);
99 if (client_fd >= 0)
100 ac->post_accept_fn(client_fd, ac, &msa, salen);
101 else
102 accept_error_check(ac);
105 return NULL;