2 * @file frescan_servers_replenishments.c
4 * @brief the replenishment data and thread for the servers
15 * This module contains the thread that waits for server's replenishment
16 * timer signals and perform the necessary replenishments.
20 * See MaRTE OS license
24 #include <time.h> // clock_gettime
26 #include <misc/freelist.h> // freelist_t
27 #include <misc/linux_list.h> // list_add_tail
28 #include <misc/timespec_operations.h>
30 #include "frescan_servers_replenishments.h"
31 #include "frescan_config.h" // FRESCAN_MX_REPL_OPS
32 #include "frescan_debug.h" // ERROR
33 #include "frescan_data.h" // frescan_repl_op_t
34 #include "fosa_threads_and_signals.h" // fosa_thread_attr_init...
37 * the_repl_op_pool - pool of replenishment operations
39 * We have a pool of replenishment operation structures and an associated
40 * freelist where we can get/put replenishment operations in O(1) time
42 * @the_repl_op_pool: array with the replenishment operations allocated
43 * @the_repl_op_pool_freelist: freelist for the_repl_op_pool
44 * @frescan_repl_op_init: initializes the freelist
45 * @frescan_repl_op_alloc: get a free replenishment operation structure
46 * @frescan_repl_op_free: free a replenishment operation structure
50 static frescan_repl_op_t the_repl_op_pool[FRESCAN_MX_REPL_OPS];
51 static freelist_t the_repl_op_pool_freelist;
53 static int frescan_repl_op_init()
55 return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
58 frescan_repl_op_t *frescan_repl_op_alloc()
62 pos = freelist_alloc(&the_repl_op_pool_freelist);
64 ERROR("could not allocate repl op\n");
67 the_repl_op_pool[pos].pool_pos = pos; // to know how to free it
68 return &the_repl_op_pool[pos];
71 int frescan_repl_op_free(frescan_repl_op_t *repl_op)
73 return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
77 * frescan_repl_thread - the thread that executes the replenishments
80 static void *frescan_repl_thread(void *arg)
86 frescan_network_t net;
87 struct list_head *pos;
88 frescan_repl_op_t *repl = NULL;
89 frescan_server_data_t *server;
90 struct itimerspec timerdata;
92 net = (frescan_network_t)(uint32_t)arg;
93 timerdata.it_interval.tv_sec = 0;
94 timerdata.it_interval.tv_nsec = 0;
97 sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
100 ret = sigwaitinfo(&set, &siginfo);
102 ERROR("sigwaitinfo failed\n");
106 if (siginfo.si_signo != FRESCAN_REPL_SIGNAL_NUM) continue;
108 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
109 "net:%u signal:%d code:%d value(server_id):%d\n",
111 siginfo.si_signo, // FRESCAN_REPL_SIGNAL_NUM
112 siginfo.si_code, // SI_TIMER
113 siginfo.si_value.sival_int); // the server id
115 id = siginfo.si_value.sival_int;
116 server = &the_servers_pool[net][id];
118 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
119 "id:%u, current_budget:%u, budget:%u, current_prio:%u\n",
121 server->current_budget,
122 server->params.values.budget,
123 server->current_priority);
125 server->current_budget++;
127 if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
128 server->current_priority = server->params.prio;
129 if (!list_empty(&server->packet_list.fifo_list)) {
130 clock_gettime (CLOCK_MONOTONIC,
135 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
136 "now... current_budget:%u, current_prio:%u\n",
137 server->current_budget,
138 server->current_priority);
140 // delete the replenishment of this call
141 list_for_each(pos, &server->replenishments.repl_list) {
142 repl = list_entry(pos, frescan_repl_op_t, repl_list);
146 list_del(&repl->repl_list);
148 ret = frescan_repl_op_free(repl);
150 ERROR("could not free replenishment op\n");
154 // check if there are pending replenishments
155 if (list_empty(&server->replenishments.repl_list)) continue;
157 list_for_each(pos, &server->replenishments.repl_list) {
158 repl = list_entry(pos, frescan_repl_op_t, repl_list);
162 timerdata.it_value = repl->when;
164 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
165 "set timer to (%d, %d)\n",
166 repl->when.tv_sec, repl->when.tv_nsec);
168 ret = timer_settime(server->repl_timer,
169 TIMER_ABSTIME, &timerdata, NULL);
171 ERROR("could not set replenishment timer\n");
180 * frescan_replenishments_init - init the replenishment structures and thread
182 * @net: the network instance
184 * Initialize the repl_op pool, set the mask for the timer signals and create
185 * the thread that will await for those signals and replenish the appropiate
189 int frescan_replenishments_init(frescan_network_t net)
192 fosa_signal_t signal_set[1];
193 fosa_thread_attr_t attr;
195 ret = frescan_repl_op_init();
197 ERROR("could not init repl_op pool\n");
201 signal_set[0] = FRESCAN_REPL_SIGNAL_NUM;
203 ret = fosa_set_accepted_signals(signal_set, 1);
205 ERROR("could not set the repl signal\n");
209 // create the replenishment thread
211 ret = fosa_thread_attr_init(&attr);
213 ERROR("could not init thread attributes\n");
217 ret = fosa_thread_attr_set_prio(&attr, FRESCAN_REPL_THREAD_PRIO);
219 ERROR("could not set repl thread prio %d\n",
220 FRESCAN_REPL_THREAD_PRIO);
224 ret = fosa_thread_create(&the_networks[net].repl_thread_id,
227 (void *)(uint32_t)net);
229 ERROR("could not create the replenishment thread\n");
233 ret = fosa_thread_attr_destroy(&attr);
235 ERROR("could not destroy thread attributes\n");
243 * frescan_replenishment_program - set a replenishment operation
245 * @net: the network instance
249 int frescan_replenishment_program(frescan_network_t net,
251 const struct timespec *timestamp)
254 frescan_repl_op_t *repl;
256 struct itimerspec timerdata;
257 frescan_server_data_t *server;
259 server = &the_servers_pool[net][ss];
261 repl = frescan_repl_op_alloc();
263 ERROR("could not allocate a repl operation\n");
267 repl->when = *timestamp;
268 incr_timespec (&repl->when, &server->params.values.period);
271 empty = list_empty(&server->replenishments.repl_list);
272 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG, "ss:%u, empty:%u\n", ss, empty);
274 list_add_tail(&repl->repl_list,
275 &server->replenishments.repl_list);
278 timerdata.it_interval.tv_sec = 0;
279 timerdata.it_interval.tv_nsec = 0;
280 timerdata.it_value = repl->when;
282 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
283 "set timer to %d sec, %d nsec\n",
284 repl->when.tv_sec, repl->when.tv_nsec);
286 ret = timer_settime(server->repl_timer,
287 TIMER_ABSTIME, &timerdata, NULL);
289 ERROR("could not set the replenishment timer\n");