]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_servers_replenishments.c_posix
error in mapping function corrected using ceil... packets constant moved to config...
[frescor/fna.git] / src_frescan / frescan_servers_replenishments.c_posix
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
26 #include <misc/freelist.h>   // freelist_t
27 #include <misc/linux_list.h> // list_add_tail
28 #include <misc/timespec_operations.h>
29
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...
35
36 /**
37  * the_repl_op_pool - pool of replenishment operations
38  *
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
41  *
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
47  *
48  */
49
50 static frescan_repl_op_t the_repl_op_pool[FRESCAN_MX_REPL_OPS];
51 static freelist_t the_repl_op_pool_freelist;
52
53 static int frescan_repl_op_init()
54 {
55         return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
56 }
57
58 frescan_repl_op_t *frescan_repl_op_alloc()
59 {
60         int pos;
61
62         pos = freelist_alloc(&the_repl_op_pool_freelist);
63         if (pos == -1) {
64                 ERROR("could not allocate repl op\n");
65                 return NULL;
66         }
67         the_repl_op_pool[pos].pool_pos = pos; // to know how to free it
68         return &the_repl_op_pool[pos];
69 }
70
71 int frescan_repl_op_free(frescan_repl_op_t *repl_op)
72 {
73         return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
74 }
75
76 /**
77  * frescan_repl_thread - the thread that executes the replenishments
78  */
79
80 static void *frescan_repl_thread(void *arg)
81 {
82         int ret;
83         sigset_t set;
84         siginfo_t siginfo;
85         frescan_ss_t id;
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;
91
92         net = (frescan_network_t)(uint32_t)arg;
93         timerdata.it_interval.tv_sec  = 0;
94         timerdata.it_interval.tv_nsec = 0;
95
96         sigemptyset(&set);
97         sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
98
99         while (1) {
100                 ret = sigwaitinfo(&set, &siginfo);
101                 if (ret == -1) {
102                         ERROR("sigwaitinfo failed\n");
103                         return NULL;
104                 }
105
106                 if (siginfo.si_signo != FRESCAN_REPL_SIGNAL_NUM) continue;
107
108                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
109                       "net:%u signal:%d code:%d value(server_id):%d\n",
110                       net,
111                       siginfo.si_signo,            // FRESCAN_REPL_SIGNAL_NUM
112                       siginfo.si_code,             // SI_TIMER
113                       siginfo.si_value.sival_int); // the server id
114
115                 id = siginfo.si_value.sival_int;
116                 server = &the_servers_pool[net][id];
117
118                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
119                       "id:%u, current_budget:%u, budget:%u, current_prio:%u\n",
120                       id,
121                       server->current_budget,
122                       server->params.values.budget,
123                       server->current_priority);
124
125                 server->current_budget++;
126
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,
131                                                &server->act_time);
132                         }
133                 }
134
135                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
136                       "now... current_budget:%u, current_prio:%u\n",
137                       server->current_budget,
138                       server->current_priority);
139
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);
143                         break;
144                 }
145
146                 list_del(&repl->repl_list);
147
148                 ret = frescan_repl_op_free(repl);
149                 if (ret != 0) {
150                         ERROR("could not free replenishment op\n");
151                         return NULL;
152                 }
153
154                 // check if there are pending replenishments
155                 if (list_empty(&server->replenishments.repl_list)) continue;
156
157                 list_for_each(pos, &server->replenishments.repl_list) {
158                         repl = list_entry(pos, frescan_repl_op_t, repl_list);
159                         break;
160                 }
161
162                 timerdata.it_value = repl->when;
163
164                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
165                       "set timer to (%d, %d)\n",
166                       repl->when.tv_sec, repl->when.tv_nsec);
167
168                 ret = timer_settime(server->repl_timer,
169                                     TIMER_ABSTIME, &timerdata, NULL);
170                 if (ret != 0) {
171                         ERROR("could not set replenishment timer\n");
172                         return NULL;
173                 }
174         }
175
176         return NULL;
177 }
178
179 /**
180  * frescan_replenishments_init - init the replenishment structures and thread
181  *
182  * @net: the network instance
183  *
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
186  * sporadic server.
187  */
188
189 int frescan_replenishments_init(frescan_network_t net)
190 {
191         int ret;
192         fosa_signal_t signal_set[1];
193         fosa_thread_attr_t attr;
194
195         ret = frescan_repl_op_init();
196         if (ret != 0) {
197                 ERROR("could not init repl_op pool\n");
198                 return ret;
199         }
200
201         signal_set[0] = FRESCAN_REPL_SIGNAL_NUM;
202
203         ret = fosa_set_accepted_signals(signal_set, 1);
204         if (ret != 0) {
205                 ERROR("could not set the repl signal\n");
206                 return ret;
207         }
208
209         // create the replenishment thread
210
211         ret = fosa_thread_attr_init(&attr);
212         if (ret != 0) {
213                 ERROR("could not init thread attributes\n");
214                 return ret;
215         }
216
217         ret = fosa_thread_attr_set_prio(&attr, FRESCAN_REPL_THREAD_PRIO);
218         if (ret != 0) {
219                 ERROR("could not set repl thread prio %d\n",
220                       FRESCAN_REPL_THREAD_PRIO);
221                 return ret;
222         }
223
224         ret = fosa_thread_create(&the_networks[net].repl_thread_id,
225                                  &attr,
226                                  frescan_repl_thread,
227                                  (void *)(uint32_t)net);
228         if (ret != 0) {
229                 ERROR("could not create the replenishment thread\n");
230                 return ret;
231         }
232
233         ret = fosa_thread_attr_destroy(&attr);
234         if (ret != 0) {
235                 ERROR("could not destroy thread attributes\n");
236                 return ret;
237         }
238
239         return 0;
240 }
241
242 /**
243  * frescan_replenishment_program - set a replenishment operation
244  *
245  * @net: the network instance
246  * @ss: the server
247  */
248
249 int frescan_replenishment_program(frescan_network_t net,
250                                   frescan_ss_t ss,
251                                   const struct timespec *timestamp)
252 {
253         int ret;
254         frescan_repl_op_t *repl;
255         bool empty;
256         struct itimerspec timerdata;
257         frescan_server_data_t *server;
258
259         server = &the_servers_pool[net][ss];
260
261         repl = frescan_repl_op_alloc();
262         if (repl == NULL) {
263                 ERROR("could not allocate a repl operation\n");
264                 return -1;
265         }
266
267         repl->when = *timestamp;
268         incr_timespec (&repl->when, &server->params.values.period);
269         repl->amount = 1;
270
271         empty = list_empty(&server->replenishments.repl_list);
272         DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG, "ss:%u, empty:%u\n", ss, empty);
273
274         list_add_tail(&repl->repl_list,
275                       &server->replenishments.repl_list);
276
277         if (empty) {
278                 timerdata.it_interval.tv_sec  = 0;
279                 timerdata.it_interval.tv_nsec = 0;
280                 timerdata.it_value = repl->when;
281
282                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
283                       "set timer to %d sec, %d nsec\n",
284                       repl->when.tv_sec, repl->when.tv_nsec);
285
286                 ret = timer_settime(server->repl_timer,
287                                     TIMER_ABSTIME, &timerdata, NULL);
288                 if (ret != 0) {
289                         ERROR("could not set the replenishment timer\n");
290                         return ret;
291                 }
292         }
293
294         return 0;
295 }