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
25 #include <assert.h> // assert
27 #include <misc/freelist.h> // freelist_t
28 #include <misc/linux_list.h> // list_add_tail
29 #include <misc/timespec_operations.h>
31 #include "frescan_servers_replenishments.h"
32 #include "frescan_config.h" // FRESCAN_MX_REPL_OPS
33 #include "frescan_debug.h" // ERROR
34 #include "frescan_data.h" // frescan_repl_op_t
35 #include "fosa_threads_and_signals.h" // fosa_thread_attr_init...
37 #if (FRESCAN_MEASURE_REPL_TH || FRESCAN_MEASURE_REPL_PROGRAM)
38 #include <misc/time_measurement_posix.h>
39 #include <misc/logger.h>
40 static time_measure_id_t measure_id;
44 * the_repl_op_pool - pool of replenishment operations
46 * We have a pool of replenishment operation structures and an associated
47 * freelist where we can get/put replenishment operations in O(1) time
49 * @the_repl_op_pool: array with the replenishment operations allocated
50 * @the_repl_op_pool_freelist: freelist for the_repl_op_pool
51 * @frescan_repl_op_init: initializes the freelist
52 * @frescan_repl_op_alloc: get a free replenishment operation structure
53 * @frescan_repl_op_free: free a replenishment operation structure
57 static frescan_repl_op_t the_repl_op_pool[FRESCAN_MX_REPL_OPS];
58 static freelist_t the_repl_op_pool_freelist;
60 static int frescan_repl_op_init()
62 return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
65 frescan_repl_op_t *frescan_repl_op_alloc()
69 pos = freelist_alloc(&the_repl_op_pool_freelist);
71 ERROR("could not allocate repl op\n");
74 the_repl_op_pool[pos].pool_pos = pos; // to know how to free it
75 return &the_repl_op_pool[pos];
78 int frescan_repl_op_free(frescan_repl_op_t *repl_op)
80 return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
84 * frescan_repl_thread - the thread that executes the replenishments
87 static void *frescan_repl_thread(void *arg)
93 frescan_network_t net;
94 frescan_server_data_t *server;
95 struct itimerspec timerdata;
97 net = (frescan_network_t)(uint32_t)arg;
98 timerdata.it_interval.tv_sec = 0;
99 timerdata.it_interval.tv_nsec = 0;
102 sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
105 #if FRESCAN_MEASURE_REPL_TH
106 ret = time_measure_posix_begin(measure_id);
109 ret = sigwaitinfo(&set, &siginfo);
112 if (siginfo.si_signo != FRESCAN_REPL_SIGNAL_NUM) continue;
114 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
115 "net:%u signal:%d code:%d value(server_id):%d\n",
117 siginfo.si_signo, // FRESCAN_REPL_SIGNAL_NUM
118 siginfo.si_code, // SI_TIMER
119 siginfo.si_value.sival_int); // the server id
121 id = siginfo.si_value.sival_int;
122 server = &the_servers_pool[net][id];
124 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
125 "id:%u current_prio:%u\n", id, server->current_priority);
127 server->current_priority = server->params.prio;
129 if (!list_empty(&server->packet_list.fifo_list)) {
130 clock_gettime (CLOCK_MONOTONIC, &server->act_time);
132 #if FRESCAN_MEASURE_REPL_TH
133 ret = time_measure_posix_end(measure_id, "thread");
136 while (logger_manual_call() > 0);
144 * frescan_replenishments_init - init the replenishment structures and thread
146 * @net: the network instance
148 * Initialize the repl_op pool, set the mask for the timer signals and create
149 * the thread that will await for those signals and replenish the appropiate
153 int frescan_replenishments_init(frescan_network_t net)
156 fosa_signal_t signal_set[1];
157 fosa_thread_attr_t attr;
159 ret = frescan_repl_op_init();
161 ERROR("could not init repl_op pool\n");
165 signal_set[0] = FRESCAN_REPL_SIGNAL_NUM;
167 ret = fosa_set_accepted_signals(signal_set, 1);
169 ERROR("could not set the repl signal\n");
173 // create the replenishment thread
174 #if (FRESCAN_MEASURE_REPL_TH || FRESCAN_MEASURE_REPL_PROGRAM)
175 ret = logger_init(LOG_ETHERNET);
178 ret = time_measure_posix_create("repl",
179 CLOCK_THREAD_CPUTIME_ID,
184 ret = fosa_thread_attr_init(&attr);
186 ERROR("could not init thread attributes\n");
190 ret = fosa_thread_attr_set_prio(&attr, FRESCAN_REPL_THREAD_PRIO);
192 ERROR("could not set repl thread prio %d\n",
193 FRESCAN_REPL_THREAD_PRIO);
197 ret = fosa_thread_create(&the_networks[net].repl_thread_id,
200 (void *)(uint32_t)net);
202 ERROR("could not create the replenishment thread\n");
206 ret = fosa_thread_attr_destroy(&attr);
208 ERROR("could not destroy thread attributes\n");
216 * frescan_replenishment_program - set a replenishment operation
218 * @net: the network instance
222 int frescan_replenishment_program(frescan_network_t net,
224 const struct timespec *timestamp)
227 frescan_repl_op_t *repl = NULL;
228 struct itimerspec timerdata;
229 frescan_server_data_t *server;
230 struct list_head *pos;
233 #if FRESCAN_MEASURE_REPL_PROGRAM
234 ret = time_measure_posix_begin(measure_id);
238 server = &the_servers_pool[net][ss];
241 list_for_each(pos, &server->replenishments.repl_list) {
242 repl = list_entry(pos, frescan_repl_op_t, repl_list);
245 list_del(&repl->repl_list);
247 // move to tail with new repl value
248 repl->when = *timestamp;
249 incr_timespec (&repl->when, &server->params.values.period);
252 list_add_tail(&repl->repl_list,
253 &server->replenishments.repl_list);
255 // check the new head
256 list_for_each(pos, &server->replenishments.repl_list) {
257 repl = list_entry(pos, frescan_repl_op_t, repl_list);
261 clock_gettime (CLOCK_MONOTONIC, &now);
263 if (smaller_timespec(&now, &repl->when)) {
264 server->current_priority = FRESCAN_BACKGROUND_PRIO;
266 timerdata.it_interval.tv_sec = 0;
267 timerdata.it_interval.tv_nsec = 0;
268 timerdata.it_value = repl->when;
270 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
271 "set timer to %d sec, %d nsec\n",
272 repl->when.tv_sec, repl->when.tv_nsec);
274 ret = timer_settime(server->repl_timer,
275 TIMER_ABSTIME, &timerdata, NULL);
277 ERROR("could not set the replenishment timer\n");
282 #if FRESCAN_MEASURE_REPL_PROGRAM
283 ret = time_measure_posix_end(measure_id, "program");
286 while (logger_manual_call() > 0);