]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_servers_replenishments.c
readme
[frescor/fna.git] / src_frescan / frescan_servers_replenishments.c
1 /*!
2  * @file frescan_servers_replenishments.c
3  *
4  * @brief the replenishment data and thread for the servers
5  *
6  * @version 0.01
7  *
8  * @date 12-Mar-2008
9  *
10  * @author
11  *      Daniel Sangorrin
12  *
13  * @comments
14  *
15  * This module contains the thread that waits for server's replenishment
16  * timer signals and perform the necessary replenishments.
17  *
18  * @license
19  *
20  * See MaRTE OS license
21  *
22  */
23
24 #include <time.h>            // clock_gettime
25 #include <assert.h>          // assert
26
27 #include <misc/freelist.h>   // freelist_t
28 #include <misc/linux_list.h> // list_add_tail
29 #include <misc/timespec_operations.h>
30
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...
36
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;
41 #endif
42
43 /**
44  * the_repl_op_pool - pool of replenishment operations
45  *
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
48  *
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
54  *
55  */
56
57 static frescan_repl_op_t the_repl_op_pool[FRESCAN_MX_REPL_OPS];
58 static freelist_t the_repl_op_pool_freelist;
59
60 static int frescan_repl_op_init()
61 {
62         return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
63 }
64
65 frescan_repl_op_t *frescan_repl_op_alloc()
66 {
67         int pos;
68
69         pos = freelist_alloc(&the_repl_op_pool_freelist);
70         if (pos == -1) {
71                 ERROR("could not allocate repl op\n");
72                 return NULL;
73         }
74         the_repl_op_pool[pos].pool_pos = pos; // to know how to free it
75         return &the_repl_op_pool[pos];
76 }
77
78 int frescan_repl_op_free(frescan_repl_op_t *repl_op)
79 {
80         return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
81 }
82
83 /**
84  * frescan_repl_thread - the thread that executes the replenishments
85  */
86
87 static void *frescan_repl_thread(void *arg)
88 {
89         int ret;
90         sigset_t set;
91         siginfo_t siginfo;
92         frescan_ss_t id;
93         frescan_network_t net;
94         frescan_server_data_t *server;
95         struct itimerspec timerdata;
96
97         net = (frescan_network_t)(uint32_t)arg;
98         timerdata.it_interval.tv_sec  = 0;
99         timerdata.it_interval.tv_nsec = 0;
100
101         sigemptyset(&set);
102         sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
103
104         while (1) {
105 #if FRESCAN_MEASURE_REPL_TH
106                 ret = time_measure_posix_begin(measure_id);
107                 assert(ret == 0);
108 #endif
109                 ret = sigwaitinfo(&set, &siginfo);
110                 assert(ret != -1);
111
112                 if (siginfo.si_signo != FRESCAN_REPL_SIGNAL_NUM) continue;
113
114                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
115                       "net:%u signal:%d code:%d value(server_id):%d\n",
116                       net,
117                       siginfo.si_signo,            // FRESCAN_REPL_SIGNAL_NUM
118                       siginfo.si_code,             // SI_TIMER
119                       siginfo.si_value.sival_int); // the server id
120
121                 id = siginfo.si_value.sival_int;
122                 server = &the_servers_pool[net][id];
123
124                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
125                       "id:%u current_prio:%u\n", id, server->current_priority);
126
127                 server->current_priority = server->params.prio;
128
129                 if (!list_empty(&server->packet_list.fifo_list)) {
130                         clock_gettime (CLOCK_MONOTONIC, &server->act_time);
131                 }
132 #if FRESCAN_MEASURE_REPL_TH
133                 ret = time_measure_posix_end(measure_id, "thread");
134                 assert(ret == 0);
135
136                 while (logger_manual_call() > 0);
137 #endif
138         }
139
140         return NULL;
141 }
142
143 /**
144  * frescan_replenishments_init - init the replenishment structures and thread
145  *
146  * @net: the network instance
147  *
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
150  * sporadic server.
151  */
152
153 int frescan_replenishments_init(frescan_network_t net)
154 {
155         int ret;
156         fosa_signal_t signal_set[1];
157         fosa_thread_attr_t attr;
158
159         ret = frescan_repl_op_init();
160         if (ret != 0) {
161                 ERROR("could not init repl_op pool\n");
162                 return ret;
163         }
164
165         signal_set[0] = FRESCAN_REPL_SIGNAL_NUM;
166
167         ret = fosa_set_accepted_signals(signal_set, 1);
168         if (ret != 0) {
169                 ERROR("could not set the repl signal\n");
170                 return ret;
171         }
172
173         // create the replenishment thread
174 #if (FRESCAN_MEASURE_REPL_TH || FRESCAN_MEASURE_REPL_PROGRAM)
175         ret = logger_init(LOG_ETHERNET);
176         assert(ret == 0);
177
178         ret = time_measure_posix_create("repl",
179                                         CLOCK_THREAD_CPUTIME_ID,
180                                         &measure_id);
181         assert(ret == 0);
182 #endif
183
184         ret = fosa_thread_attr_init(&attr);
185         if (ret != 0) {
186                 ERROR("could not init thread attributes\n");
187                 return ret;
188         }
189
190         ret = fosa_thread_attr_set_prio(&attr, FRESCAN_REPL_THREAD_PRIO);
191         if (ret != 0) {
192                 ERROR("could not set repl thread prio %d\n",
193                       FRESCAN_REPL_THREAD_PRIO);
194                 return ret;
195         }
196
197         ret = fosa_thread_create(&the_networks[net].repl_thread_id,
198                                  &attr,
199                                  frescan_repl_thread,
200                                  (void *)(uint32_t)net);
201         if (ret != 0) {
202                 ERROR("could not create the replenishment thread\n");
203                 return ret;
204         }
205
206         ret = fosa_thread_attr_destroy(&attr);
207         if (ret != 0) {
208                 ERROR("could not destroy thread attributes\n");
209                 return ret;
210         }
211
212         return 0;
213 }
214
215 /**
216  * frescan_replenishment_program - set a replenishment operation
217  *
218  * @net: the network instance
219  * @ss: the server
220  */
221
222 int frescan_replenishment_program(frescan_network_t net,
223                                   frescan_ss_t ss,
224                                   const struct timespec *timestamp)
225 {
226         int ret;
227         frescan_repl_op_t *repl = NULL;
228         struct itimerspec timerdata;
229         frescan_server_data_t *server;
230         struct list_head *pos;
231         struct timespec now;
232
233 #if FRESCAN_MEASURE_REPL_PROGRAM
234         ret = time_measure_posix_begin(measure_id);
235         assert(ret == 0);
236 #endif
237
238         server = &the_servers_pool[net][ss];
239
240         // extract the head
241         list_for_each(pos, &server->replenishments.repl_list) {
242                 repl = list_entry(pos, frescan_repl_op_t, repl_list);
243                 break;
244         }
245         list_del(&repl->repl_list);
246
247         // move to tail with new repl value
248         repl->when = *timestamp;
249         incr_timespec (&repl->when, &server->params.values.period);
250         repl->amount = 1;
251
252         list_add_tail(&repl->repl_list,
253                        &server->replenishments.repl_list);
254
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);
258                 break;
259         }
260
261         clock_gettime (CLOCK_MONOTONIC, &now);
262
263         if (smaller_timespec(&now, &repl->when)) {
264                 server->current_priority = FRESCAN_BACKGROUND_PRIO;
265
266                 timerdata.it_interval.tv_sec  = 0;
267                 timerdata.it_interval.tv_nsec = 0;
268                 timerdata.it_value = repl->when;
269
270                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
271                       "set timer to %d sec, %d nsec\n",
272                       repl->when.tv_sec, repl->when.tv_nsec);
273
274                 ret = timer_settime(server->repl_timer,
275                                     TIMER_ABSTIME, &timerdata, NULL);
276                 if (ret != 0) {
277                         ERROR("could not set the replenishment timer\n");
278                         return ret;
279                 }
280         }
281
282 #if FRESCAN_MEASURE_REPL_PROGRAM
283                 ret = time_measure_posix_end(measure_id, "program");
284                 assert(ret == 0);
285
286                 while (logger_manual_call() > 0);
287 #endif
288
289         return 0;
290 }