kore

Kore is a web application platform for writing scalable, concurrent web based processes in C or Python.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

linux.c (5685B)



      1 /*
      2  * Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <sys/param.h>
     18 #include <sys/random.h>
     19 #include <sys/epoll.h>
     20 #include <sys/sendfile.h>
     21 #include <sys/syscall.h>
     22 
     23 #include <sched.h>
     24 
     25 #include "kore.h"
     26 #include "seccomp.h"
     27 
     28 #if defined(KORE_USE_PGSQL)
     29 #include "pgsql.h"
     30 #endif
     31 
     32 #if defined(KORE_USE_TASKS)
     33 #include "tasks.h"
     34 #endif
     35 
     36 static int			efd = -1;
     37 static u_int32_t		event_count = 0;
     38 static struct epoll_event	*events = NULL;
     39 
     40 void
     41 kore_platform_init(void)
     42 {
     43 	long		n;
     44 
     45 	kore_seccomp_init();
     46 
     47 	if ((n = sysconf(_SC_NPROCESSORS_ONLN)) == -1) {
     48 		cpu_count = 1;
     49 	} else {
     50 		cpu_count = (u_int16_t)n;
     51 	}
     52 }
     53 
     54 void
     55 kore_platform_worker_setcpu(struct kore_worker *kw)
     56 {
     57 	cpu_set_t	cpuset;
     58 
     59 	CPU_ZERO(&cpuset);
     60 	CPU_SET(kw->cpu, &cpuset);
     61 
     62 	if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) == -1)
     63 		kore_log(LOG_NOTICE, "kore_worker_setcpu(): %s", errno_s);
     64 }
     65 
     66 void
     67 kore_platform_event_init(void)
     68 {
     69 	if (efd != -1)
     70 		close(efd);
     71 	if (events != NULL)
     72 		kore_free(events);
     73 
     74 	if ((efd = epoll_create(10000)) == -1)
     75 		fatal("epoll_create(): %s", errno_s);
     76 
     77 	event_count = worker_max_connections + nlisteners;
     78 	events = kore_calloc(event_count, sizeof(struct epoll_event));
     79 }
     80 
     81 void
     82 kore_platform_event_cleanup(void)
     83 {
     84 	if (efd != -1) {
     85 		close(efd);
     86 		efd = -1;
     87 	}
     88 
     89 	if (events != NULL) {
     90 		kore_free(events);
     91 		events = NULL;
     92 	}
     93 }
     94 
     95 void
     96 kore_platform_event_wait(u_int64_t timer)
     97 {
     98 	u_int32_t		r;
     99 	struct kore_event	*evt;
    100 	int			n, i, timeo;
    101 
    102 	if (timer == KORE_WAIT_INFINITE)
    103 		timeo = -1;
    104 	else
    105 		timeo = timer;
    106 
    107 	n = epoll_wait(efd, events, event_count, timeo);
    108 	if (n == -1) {
    109 		if (errno == EINTR)
    110 			return;
    111 		fatal("epoll_wait(): %s", errno_s);
    112 	}
    113 
    114 	r = 0;
    115 	for (i = 0; i < n; i++) {
    116 		if (events[i].data.ptr == NULL)
    117 			fatal("events[%d].data.ptr == NULL", i);
    118 
    119 		r = 0;
    120 		evt = (struct kore_event *)events[i].data.ptr;
    121 
    122 		if (events[i].events & EPOLLIN)
    123 			evt->flags |= KORE_EVENT_READ;
    124 
    125 		if (events[i].events & EPOLLOUT)
    126 			evt->flags |= KORE_EVENT_WRITE;
    127 
    128 		if (events[i].events & EPOLLERR ||
    129 		    events[i].events & EPOLLHUP ||
    130 		    events[i].events & EPOLLRDHUP)
    131 			r = 1;
    132 
    133 		evt->handle(events[i].data.ptr, r);
    134 	}
    135 }
    136 
    137 void
    138 kore_platform_event_level_all(int fd, void *c)
    139 {
    140 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLOUT | EPOLLRDHUP, 0, c);
    141 }
    142 
    143 void
    144 kore_platform_event_level_read(int fd, void *c)
    145 {
    146 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLRDHUP, 0, c);
    147 }
    148 
    149 void
    150 kore_platform_event_all(int fd, void *c)
    151 {
    152 	kore_platform_event_schedule(fd,
    153 	    EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET, 0, c);
    154 }
    155 
    156 void
    157 kore_platform_event_schedule(int fd, int type, int flags, void *udata)
    158 {
    159 	struct epoll_event	evt;
    160 
    161 	evt.events = type;
    162 	evt.data.ptr = udata;
    163 	if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &evt) == -1) {
    164 		if (errno == EEXIST) {
    165 			if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &evt) == -1)
    166 				fatal("epoll_ctl() MOD: %s", errno_s);
    167 		} else {
    168 			fatal("epoll_ctl() ADD: %s", errno_s);
    169 		}
    170 	}
    171 }
    172 
    173 void
    174 kore_platform_schedule_read(int fd, void *data)
    175 {
    176 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLET, 0, data);
    177 }
    178 
    179 void
    180 kore_platform_schedule_write(int fd, void *data)
    181 {
    182 	kore_platform_event_schedule(fd, EPOLLOUT | EPOLLET, 0, data);
    183 }
    184 
    185 void
    186 kore_platform_disable_read(int fd)
    187 {
    188 	if (epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) == -1)
    189 		fatal("kore_platform_disable_read: %s", errno_s);
    190 }
    191 
    192 void
    193 kore_platform_enable_accept(void)
    194 {
    195 	struct listener		*l;
    196 	struct kore_server	*srv;
    197 
    198 	LIST_FOREACH(srv, &kore_servers, list) {
    199 		LIST_FOREACH(l, &srv->listeners, list)
    200 			kore_platform_event_schedule(l->fd, EPOLLIN, 0, l);
    201 	}
    202 }
    203 
    204 void
    205 kore_platform_disable_accept(void)
    206 {
    207 	struct listener		*l;
    208 	struct kore_server	*srv;
    209 
    210 	LIST_FOREACH(srv, &kore_servers, list) {
    211 		LIST_FOREACH(l, &srv->listeners, list) {
    212 			if (epoll_ctl(efd, EPOLL_CTL_DEL, l->fd, NULL) == -1) {
    213 				fatal("kore_platform_disable_accept: %s",
    214 				    errno_s);
    215 			}
    216 		}
    217 	}
    218 }
    219 
    220 void
    221 kore_platform_proctitle(const char *title)
    222 {
    223 	kore_proctitle(title);
    224 }
    225 
    226 #if defined(KORE_USE_PLATFORM_SENDFILE)
    227 int
    228 kore_platform_sendfile(struct connection *c, struct netbuf *nb)
    229 {
    230 	off_t		smin;
    231 	ssize_t		sent;
    232 	size_t		len, prevoff;
    233 
    234 	prevoff = nb->fd_off;
    235 	smin = nb->fd_len - nb->fd_off;
    236 	len = MIN(SENDFILE_PAYLOAD_MAX, smin);
    237 
    238 resend:
    239 	sent = sendfile(c->fd, nb->file_ref->fd, &nb->fd_off, len);
    240 	if (sent == -1) {
    241 		if (errno == EAGAIN) {
    242 			c->evt.flags &= ~KORE_EVENT_WRITE;
    243 			return (KORE_RESULT_OK);
    244 		}
    245 
    246 		return (KORE_RESULT_ERROR);
    247 	}
    248 
    249 	if (nb->fd_off - prevoff != (size_t)len)
    250 		goto resend;
    251 
    252 	if (sent == 0 || nb->fd_off == nb->fd_len) {
    253 		net_remove_netbuf(c, nb);
    254 		c->snb = NULL;
    255 	}
    256 
    257 	return (KORE_RESULT_OK);
    258 }
    259 #endif
    260 
    261 void
    262 kore_platform_sandbox(void)
    263 {
    264 	kore_seccomp_enable();
    265 }
    266 
    267 u_int32_t
    268 kore_platform_random_uint32(void)
    269 {
    270 	ssize_t		ret;
    271 	u_int32_t	val;
    272 
    273 	if ((ret = getrandom(&val, sizeof(val), 0)) == -1)
    274 		fatalx("getrandom(): %s", errno_s);
    275 
    276 	if ((size_t)ret != sizeof(val))
    277 		fatalx("getrandom() %zd != %zu", ret, sizeof(val));
    278 
    279 	return (val);
    280 }