netif_utils: correctly close fd on read error
[project/ustp.git] / worker.c
1 /*
2 * ustp - OpenWrt STP/RSTP/MSTP daemon
3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14 #include <pthread.h>
15 #include <string.h>
16 #include <stdlib.h>
17
18 #include <libubox/uloop.h>
19 #include <libubox/utils.h>
20
21 #include "worker.h"
22 #include "bridge_ctl.h"
23 #include "bridge_track.h"
24 #include "packet.h"
25
26 static pthread_t w_thread;
27 static pthread_mutex_t w_lock = PTHREAD_MUTEX_INITIALIZER;
28 static pthread_cond_t w_cond = PTHREAD_COND_INITIALIZER;
29 static LIST_HEAD(w_queue);
30 static struct uloop_timeout w_timer;
31
32 struct worker_queued_event {
33 struct list_head list;
34 struct worker_event ev;
35 };
36
37 static struct worker_event *worker_next_event(void)
38 {
39 struct worker_queued_event *ev;
40 static struct worker_event ev_data;
41
42 pthread_mutex_lock(&w_lock);
43 while (list_empty(&w_queue))
44 pthread_cond_wait(&w_cond, &w_lock);
45
46 ev = list_first_entry(&w_queue, struct worker_queued_event, list);
47 list_del(&ev->list);
48 pthread_mutex_unlock(&w_lock);
49
50 memcpy(&ev_data, &ev->ev, sizeof(ev_data));
51 free(ev);
52
53 return &ev_data;
54 }
55
56 static void
57 handle_worker_event(struct worker_event *ev)
58 {
59 switch (ev->type) {
60 case WORKER_EV_ONE_SECOND:
61 bridge_one_second();
62 break;
63 case WORKER_EV_BRIDGE_EVENT:
64 bridge_event_handler();
65 break;
66 case WORKER_EV_RECV_PACKET:
67 packet_rcv();
68 break;
69 case WORKER_EV_BRIDGE_ADD:
70 bridge_create(ev->bridge_idx, &ev->bridge_config);
71 break;
72 case WORKER_EV_BRIDGE_REMOVE:
73 bridge_delete(ev->bridge_idx);
74 break;
75 default:
76 return;
77 }
78 }
79
80 static void *worker_thread_fn(void *arg)
81 {
82 struct worker_event *ev;
83
84 while (1) {
85 ev = worker_next_event();
86 if (ev->type == WORKER_EV_SHUTDOWN)
87 break;
88
89 handle_worker_event(ev);
90 }
91
92 return NULL;
93 }
94
95 static void worker_timer_cb(struct uloop_timeout *t)
96 {
97 struct worker_event ev = {
98 .type = WORKER_EV_ONE_SECOND,
99 };
100
101 uloop_timeout_set(t, 1000);
102 worker_queue_event(&ev);
103 }
104
105 int worker_init(void)
106 {
107 w_timer.cb = worker_timer_cb;
108 uloop_timeout_set(&w_timer, 1000);
109
110 return pthread_create(&w_thread, NULL, worker_thread_fn, NULL);
111 }
112
113 void worker_cleanup(void)
114 {
115 struct worker_event ev = {
116 .type = WORKER_EV_SHUTDOWN,
117 };
118
119 worker_queue_event(&ev);
120 pthread_join(w_thread, NULL);
121 }
122
123 void worker_queue_event(struct worker_event *ev)
124 {
125 struct worker_queued_event *evc;
126
127 evc = malloc(sizeof(*evc));
128 memcpy(&evc->ev, ev, sizeof(*ev));
129
130 pthread_mutex_lock(&w_lock);
131 list_add_tail(&evc->list, &w_queue);
132 pthread_mutex_unlock(&w_lock);
133
134 pthread_cond_signal(&w_cond);
135 }