]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_servers_replenishments.c
383f17e9fafc948960d06f408a987654d69b9cd6
[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
35 /**
36  * the_repl_op_pool - pool of replenishment operations
37  *
38  * We have a pool of replenishment operation structures and an associated
39  * freelist where we can get/put replenishment operations in O(1) time
40  *
41  * @the_repl_op_pool: array with the replenishment operations allocated
42  * @the_repl_op_pool_freelist: freelist for the_repl_op_pool
43  * @frescan_repl_op_init: initializes the freelist
44  * @frescan_repl_op_alloc: get a free replenishment operation structure
45  * @frescan_repl_op_free: free a replenishment operation structure
46  *
47  */
48
49 static frescan_repl_op_t the_repl_op_pool[FRESCAN_MX_REPL_OPS];
50 static freelist_t the_repl_op_pool_freelist;
51
52 static int frescan_repl_op_init()
53 {
54         return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
55 }
56
57 static frescan_repl_op_t *frescan_repl_op_alloc()
58 {
59         int pos;
60
61         pos = freelist_alloc(&the_repl_op_pool_freelist);
62         if (pos == -1) {
63                 ERROR("could not allocate repl op\n");
64                 return NULL;
65         }
66         the_repl_op_pool[pos].pool_pos = pos; // to know how to free it
67         return &the_repl_op_pool[pos];
68 }
69
70 static int frescan_repl_op_free(frescan_repl_op_t *repl_op)
71 {
72         return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
73 }
74
75 /**
76  * frescan_repl_thread - the thread that executes the replenishments
77  */
78
79 static void *frescan_repl_thread(void *arg)
80 {
81         int ret;
82         sigset_t set;
83         siginfo_t siginfo;
84         frescan_ss_t id;
85         frescan_network_t net;
86         struct list_head *pos;
87         frescan_repl_op_t *repl;
88         frescan_server_data_t *server;
89         struct itimerspec timerdata;
90
91         net = (frescan_network_t)(uint32_t)arg;
92         timerdata.it_interval.tv_sec  = 0;
93         timerdata.it_interval.tv_nsec = 0;
94
95         sigemptyset(&set);
96         sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
97
98         while (1) {
99                 ret = sigwaitinfo(&set, &siginfo);
100                 if (ret == -1) {
101                         ERROR("sigwaitinfo failed\n");
102                         return NULL;
103                 }
104
105                 if (siginfo.si_signo != FRESCAN_REPL_SIGNAL_NUM) continue;
106
107                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
108                       "net:%u signal:%d code:%d value(server_id):%d\n",
109                       net,
110                       siginfo.si_signo,            // FRESCAN_REPL_SIGNAL_NUM
111                       siginfo.si_code,             // SI_TIMER
112                       siginfo.si_value.sival_int); // the server id
113
114                 id = siginfo.si_value.sival_int;
115                 server = &the_servers_pool[net][id];
116
117                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
118                       "id:%u, current_budget:%u, budget:%u, current_prio:%u\n",
119                       id,
120                       server->current_budget,
121                       server->params.budget,
122                       server->current_priority);
123
124                 server->current_budget++;
125
126                 if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
127                         server->current_priority = server->params.prio;
128                 }
129
130                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
131                       "now... current_budget:%u, current_prio:%u\n",
132                       server->current_budget,
133                       server->current_priority);
134
135                 // delete the replenishment of this call
136                 list_for_each(pos, &server->replenishments.repl_list) {
137                         repl = list_entry(pos, frescan_repl_op_t, repl_list);
138                         break;
139                 }
140
141                 list_del(&repl->repl_list);
142
143                 ret = frescan_repl_op_free(repl);
144                 if (ret != 0) {
145                         ERROR("could not free replenishment op\n");
146                         return NULL;
147                 }
148
149                 // check if there are pending replenishments
150                 if (list_empty(&server->replenishments.repl_list)) continue;
151
152                 list_for_each(pos, &server->replenishments.repl_list) {
153                         repl = list_entry(pos, frescan_repl_op_t, repl_list);
154                         break;
155                 }
156
157                 timerdata.it_value = repl->when;
158
159                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
160                       "set timer to %d sec, %d nsec\n",
161                       repl->when.tv_sec, repl->when.tv_nsec);
162
163                 ret = timer_settime(server->repl_timer,
164                                     TIMER_ABSTIME, &timerdata, NULL);
165                 if (ret != 0) {
166                         ERROR("could not set replenishment timer\n");
167                         return NULL;
168                 }
169         }
170
171         return NULL;
172 }
173
174 /**
175  * frescan_replenishments_init - init the replenishment structures and thread
176  *
177  * @net: the network instance
178  *
179  * Initialize the repl_op pool, set the mask for the timer signals and create
180  * the thread that will await for those signals and replenish the appropiate
181  * sporadic server.
182  */
183
184 int frescan_replenishments_init(frescan_network_t net)
185 {
186         int ret;
187         sigset_t set;
188         struct sigaction action;
189
190         ret = frescan_repl_op_init();
191         if (ret != 0) {
192                 ERROR("could not init repl_op pool\n");
193                 return ret;
194         }
195
196         sigemptyset(&set);
197         sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
198
199         ret = pthread_sigmask(SIG_BLOCK, &set, NULL);
200         if (ret != 0) {
201                 ERROR("could not put the signal mask for replenishments\n");
202                 return ret;
203         }
204
205         // the following is unnecesary in MaRTE OS because all signals are RT
206         action.sa_handler = SIG_DFL;
207         sigemptyset(&action.sa_mask);
208         action.sa_flags = SA_SIGINFO;
209         ret = sigaction (FRESCAN_REPL_SIGNAL_NUM, &action, NULL);
210         if (ret != 0) {
211                 ERROR("could not set action for the repl signal\n");
212                 return ret;
213         }
214
215         // TODO: set the pthread attributes
216         ret = pthread_create(&the_networks[net].repl_thread_id,
217                               NULL,
218                               frescan_repl_thread,
219                               (void *)(uint32_t)net);
220         if (ret != 0) {
221                 ERROR("could not create the replenishment thread\n");
222                 return ret;
223         }
224
225         return 0;
226 }
227
228 /**
229  * frescan_replenishment_program - set a replenishment operation
230  *
231  * @net: the network instance
232  * @ss: the server
233  */
234
235 int frescan_replenishment_program(frescan_network_t net,
236                                   frescan_ss_t ss)
237 {
238         int ret;
239         frescan_repl_op_t *repl;
240         bool empty;
241         struct itimerspec timerdata;
242         frescan_server_data_t *server;
243
244         server = &the_servers_pool[net][ss];
245
246         if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
247                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG, "ss in background\n");
248                 return 0;
249         }
250
251         repl = frescan_repl_op_alloc();
252         if (repl == NULL) {
253                 ERROR("could not allocate a repl operation\n");
254                 return -1;
255         }
256
257         clock_gettime (CLOCK_MONOTONIC, &repl->when);
258         incr_timespec (&repl->when, &server->params.period);
259         repl->amount = 1;
260
261         empty = list_empty(&server->replenishments.repl_list);
262         DEBUG(FRESCAN_REPL_ENABLE_DEBUG, "ss:%u, empty:%u\n", ss, empty);
263
264         list_add_tail(&repl->repl_list,
265                       &server->replenishments.repl_list);
266
267         if (empty) {
268                 timerdata.it_interval.tv_sec  = 0;
269                 timerdata.it_interval.tv_nsec = 0;
270                 timerdata.it_value = repl->when;
271
272                 DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
273                       "set timer to %d sec, %d nsec\n",
274                       repl->when.tv_sec, repl->when.tv_nsec);
275
276                 ret = timer_settime(server->repl_timer,
277                                     TIMER_ABSTIME, &timerdata, NULL);
278                 if (ret != 0) {
279                         ERROR("could not set the replenishment timer\n");
280                         return ret;
281                 }
282         }
283
284         return 0;
285 }