]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_servers_replenishments.c
c47fb1846d3e09c4a77d1e970b1841d61f4d544a
[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
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 static 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 static 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_REPL_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_REPL_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                 }
130
131                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
132                       "now... current_budget:%u, current_prio:%u\n",
133                       server->current_budget,
134                       server->current_priority);
135
136                 // delete the replenishment of this call
137                 list_for_each(pos, &server->replenishments.repl_list) {
138                         repl = list_entry(pos, frescan_repl_op_t, repl_list);
139                         break;
140                 }
141
142                 list_del(&repl->repl_list);
143
144                 ret = frescan_repl_op_free(repl);
145                 if (ret != 0) {
146                         ERROR("could not free replenishment op\n");
147                         return NULL;
148                 }
149
150                 // check if there are pending replenishments
151                 if (list_empty(&server->replenishments.repl_list)) continue;
152
153                 list_for_each(pos, &server->replenishments.repl_list) {
154                         repl = list_entry(pos, frescan_repl_op_t, repl_list);
155                         break;
156                 }
157
158                 timerdata.it_value = repl->when;
159
160                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
161                       "set timer to %d sec, %d nsec\n",
162                       repl->when.tv_sec, repl->when.tv_nsec);
163
164                 ret = timer_settime(server->repl_timer,
165                                     TIMER_ABSTIME, &timerdata, NULL);
166                 if (ret != 0) {
167                         ERROR("could not set replenishment timer\n");
168                         return NULL;
169                 }
170         }
171
172         return NULL;
173 }
174
175 /**
176  * frescan_replenishments_init - init the replenishment structures and thread
177  *
178  * @net: the network instance
179  *
180  * Initialize the repl_op pool, set the mask for the timer signals and create
181  * the thread that will await for those signals and replenish the appropiate
182  * sporadic server.
183  */
184
185 int frescan_replenishments_init(frescan_network_t net)
186 {
187         int ret;
188         fosa_signal_t signal_set[1];
189         fosa_thread_attr_t attr;
190
191         ret = frescan_repl_op_init();
192         if (ret != 0) {
193                 ERROR("could not init repl_op pool\n");
194                 return ret;
195         }
196
197         signal_set[0] = FRESCAN_REPL_SIGNAL_NUM;
198
199         ret = fosa_set_accepted_signals(signal_set, 1);
200         if (ret != 0) {
201                 ERROR("could not set the repl signal\n");
202                 return ret;
203         }
204
205         // create the replenishment thread
206
207         ret = fosa_thread_attr_init(&attr);
208         if (ret != 0) {
209                 ERROR("could not init thread attributes\n");
210                 return ret;
211         }
212
213         ret = fosa_thread_attr_set_prio(&attr, FRESCAN_REPL_THREAD_PRIO);
214         if (ret != 0) {
215                 ERROR("could not set repl thread prio %d\n",
216                       FRESCAN_REPL_THREAD_PRIO);
217                 return ret;
218         }
219
220         ret = fosa_thread_create(&the_networks[net].repl_thread_id,
221                                  &attr,
222                                  frescan_repl_thread,
223                                  (void *)(uint32_t)net);
224         if (ret != 0) {
225                 ERROR("could not create the replenishment thread\n");
226                 return ret;
227         }
228
229         ret = fosa_thread_attr_destroy(&attr);
230         if (ret != 0) {
231                 ERROR("could not destroy thread attributes\n");
232                 return ret;
233         }
234
235         return 0;
236 }
237
238 /**
239  * frescan_replenishment_program - set a replenishment operation
240  *
241  * @net: the network instance
242  * @ss: the server
243  */
244
245 int frescan_replenishment_program(frescan_network_t net,
246                                   frescan_ss_t ss)
247 {
248         int ret;
249         frescan_repl_op_t *repl;
250         bool empty;
251         struct itimerspec timerdata;
252         frescan_server_data_t *server;
253
254         server = &the_servers_pool[net][ss];
255
256         if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
257                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG, "ss in background\n");
258                 return 0;
259         }
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         clock_gettime (CLOCK_MONOTONIC, &repl->when);
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_REPL_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_REPL_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 }