]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_servers_replenishments.c
use frsh_contract_t structure instead of the old frescan_contract_t structure.. we...
[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  * -----------------------------------------------------------------------
21  *  Copyright (C) 2006 - 2008 FRESCOR consortium partners:
22  *
23  *    Universidad de Cantabria,              SPAIN
24  *    University of York,                    UK
25  *    Scuola Superiore Sant'Anna,            ITALY
26  *    Kaiserslautern University,             GERMANY
27  *    Univ. Politécnica  Valencia,           SPAIN
28  *    Czech Technical University in Prague,  CZECH REPUBLIC
29  *    ENEA                                   SWEDEN
30  *    Thales Communication S.A.              FRANCE
31  *    Visual Tools S.A.                      SPAIN
32  *    Rapita Systems Ltd                     UK
33  *    Evidence                               ITALY
34  *
35  *    See http://www.frescor.org for a link to partners' websites
36  *
37  *           FRESCOR project (FP6/2005/IST/5-034026) is funded
38  *        in part by the European Union Sixth Framework Programme
39  *        The European Union is not liable of any use that may be
40  *        made of this code.
41  *
42  *  This file is part of FRESCAN
43  *
44  *  FRESCAN is free software; you can  redistribute it and/or  modify
45  *  it under the terms of  the GNU General Public License as published by
46  *  the Free Software Foundation;  either  version 2, or (at  your option)
47  *  any later version.
48  *
49  *  FRESCAN  is distributed  in  the hope  that  it  will  be useful,  but
50  *  WITHOUT  ANY  WARRANTY;     without  even the   implied   warranty  of
51  *  MERCHANTABILITY  or  FITNESS FOR  A  PARTICULAR PURPOSE. See  the  GNU
52  *  General Public License for more details.
53  *
54  *  You should have  received a  copy of  the  GNU  General Public License
55  *  distributed  with  FRESCAN;  see file COPYING.   If not,  write to the
56  *  Free Software  Foundation,  59 Temple Place  -  Suite 330,  Boston, MA
57  *  02111-1307, USA.
58  *
59  * As a special exception, including FRESCAN header files in a file,
60  * instantiating FRESCAN generics or templates, or linking other files
61  * with FRESCAN objects to produce an executable application, does not
62  * by itself cause the resulting executable application to be covered
63  * by the GNU General Public License. This exception does not
64  * however invalidate any other reasons why the executable file might be
65  * covered by the GNU Public License.
66  * -----------------------------------------------------------------------
67  *
68  */
69
70 #include <time.h>            // clock_gettime
71 #include <assert.h>          // assert
72
73 #include <misc/freelist.h>   // freelist_t
74 #include <misc/linux_list.h> // list_add_tail
75 #include <misc/timespec_operations.h>
76
77 #include "frescan_servers_replenishments.h"
78 #include "frescan_config.h"  // FRESCAN_MX_REPL_OPS
79 #include "frescan_debug.h"   // ERROR
80 #include "frescan_data.h"    // frescan_repl_op_t
81 #include "fosa_threads_and_signals.h" // fosa_thread_attr_init...
82
83 #if (FRESCAN_MEASURE_REPL_TH || FRESCAN_MEASURE_REPL_PROGRAM)
84 #include <misc/time_measurement_posix.h>
85 #include <misc/logger.h>
86 static time_measure_id_t measure_id;
87 #endif
88
89 /**
90  * the_repl_op_pool - pool of replenishment operations
91  *
92  * We have a pool of replenishment operation structures and an associated
93  * freelist where we can get/put replenishment operations in O(1) time
94  *
95  * @the_repl_op_pool: array with the replenishment operations allocated
96  * @the_repl_op_pool_freelist: freelist for the_repl_op_pool
97  * @frescan_repl_op_init: initializes the freelist
98  * @frescan_repl_op_alloc: get a free replenishment operation structure
99  * @frescan_repl_op_free: free a replenishment operation structure
100  *
101  */
102
103 static frescan_repl_op_t the_repl_op_pool[FRESCAN_MX_REPL_OPS];
104 static freelist_t the_repl_op_pool_freelist;
105
106 static int frescan_repl_op_init()
107 {
108         return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
109 }
110
111 frescan_repl_op_t *frescan_repl_op_alloc()
112 {
113         int pos;
114
115         pos = freelist_alloc(&the_repl_op_pool_freelist);
116         if (pos == -1) {
117                 ERROR("could not allocate repl op\n");
118                 return NULL;
119         }
120         the_repl_op_pool[pos].pool_pos = pos; // to know how to free it
121         return &the_repl_op_pool[pos];
122 }
123
124 int frescan_repl_op_free(frescan_repl_op_t *repl_op)
125 {
126         return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
127 }
128
129 /**
130  * frescan_repl_thread - the thread that executes the replenishments
131  */
132
133 static void *frescan_repl_thread(void *arg)
134 {
135         int ret;
136         sigset_t set;
137         siginfo_t siginfo;
138         frescan_ss_t id;
139         frescan_network_t net;
140         frescan_server_data_t *server;
141         struct itimerspec timerdata;
142
143         net = (frescan_network_t)(uint32_t)arg;
144         timerdata.it_interval.tv_sec  = 0;
145         timerdata.it_interval.tv_nsec = 0;
146
147         sigemptyset(&set);
148         sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
149
150         while (1) {
151 #if FRESCAN_MEASURE_REPL_TH
152                 ret = time_measure_posix_begin(measure_id);
153                 assert(ret == 0);
154 #endif
155                 ret = sigwaitinfo(&set, &siginfo);
156                 assert(ret != -1);
157
158                 if (siginfo.si_signo != FRESCAN_REPL_SIGNAL_NUM) continue;
159
160                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
161                       "net:%u signal:%d code:%d value(server_id):%d\n",
162                       net,
163                       siginfo.si_signo,            // FRESCAN_REPL_SIGNAL_NUM
164                       siginfo.si_code,             // SI_TIMER
165                       siginfo.si_value.sival_int); // the server id
166
167                 id = siginfo.si_value.sival_int;
168                 server = &the_servers_pool[net][id];
169
170                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
171                       "id:%u current_prio:%u\n", id, server->current_priority);
172
173                 server->current_priority = server->params.prio;
174
175                 if (!list_empty(&server->packet_list.fifo_list)) {
176                         clock_gettime (CLOCK_MONOTONIC, &server->act_time);
177                 }
178 #if FRESCAN_MEASURE_REPL_TH
179                 ret = time_measure_posix_end(measure_id, "thread");
180                 assert(ret == 0);
181
182                 while (logger_manual_call() > 0);
183 #endif
184         }
185
186         return NULL;
187 }
188
189 /**
190  * frescan_replenishments_init - init the replenishment structures and thread
191  *
192  * @net: the network instance
193  *
194  * Initialize the repl_op pool, set the mask for the timer signals and create
195  * the thread that will await for those signals and replenish the appropiate
196  * sporadic server.
197  */
198
199 int frescan_replenishments_init(frescan_network_t net)
200 {
201         int ret;
202         fosa_signal_t signal_set[1];
203         fosa_thread_attr_t attr;
204
205         ret = frescan_repl_op_init();
206         if (ret != 0) {
207                 ERROR("could not init repl_op pool\n");
208                 return ret;
209         }
210
211         signal_set[0] = FRESCAN_REPL_SIGNAL_NUM;
212
213         ret = fosa_set_accepted_signals(signal_set, 1);
214         if (ret != 0) {
215                 ERROR("could not set the repl signal\n");
216                 return ret;
217         }
218
219         // create the replenishment thread
220 #if (FRESCAN_MEASURE_REPL_TH || FRESCAN_MEASURE_REPL_PROGRAM)
221         ret = logger_init(LOG_ETHERNET);
222         assert(ret == 0);
223
224         ret = time_measure_posix_create("repl",
225                                         CLOCK_THREAD_CPUTIME_ID,
226                                         &measure_id);
227         assert(ret == 0);
228 #endif
229
230         ret = fosa_thread_attr_init(&attr);
231         if (ret != 0) {
232                 ERROR("could not init thread attributes\n");
233                 return ret;
234         }
235
236         ret = fosa_thread_attr_set_prio(&attr, FRESCAN_REPL_THREAD_PRIO);
237         if (ret != 0) {
238                 ERROR("could not set repl thread prio %d\n",
239                       FRESCAN_REPL_THREAD_PRIO);
240                 return ret;
241         }
242
243         ret = fosa_thread_create(&the_networks[net].repl_thread_id,
244                                  &attr,
245                                  frescan_repl_thread,
246                                  (void *)(uint32_t)net);
247         if (ret != 0) {
248                 ERROR("could not create the replenishment thread\n");
249                 return ret;
250         }
251
252         ret = fosa_thread_attr_destroy(&attr);
253         if (ret != 0) {
254                 ERROR("could not destroy thread attributes\n");
255                 return ret;
256         }
257
258         return 0;
259 }
260
261 /**
262  * frescan_replenishment_program - set a replenishment operation
263  *
264  * @net: the network instance
265  * @ss: the server
266  */
267
268 int frescan_replenishment_program(frescan_network_t net,
269                                   frescan_ss_t ss,
270                                   const struct timespec *timestamp)
271 {
272         int ret;
273         frescan_repl_op_t *repl = NULL;
274         struct itimerspec timerdata;
275         frescan_server_data_t *server;
276         struct list_head *pos;
277         struct timespec now;
278
279 #if FRESCAN_MEASURE_REPL_PROGRAM
280         ret = time_measure_posix_begin(measure_id);
281         assert(ret == 0);
282 #endif
283
284         server = &the_servers_pool[net][ss];
285
286         // extract the head
287         list_for_each(pos, &server->replenishments.repl_list) {
288                 repl = list_entry(pos, frescan_repl_op_t, repl_list);
289                 break;
290         }
291         list_del(&repl->repl_list);
292
293         // move to tail with new repl value
294         repl->when = *timestamp;
295         incr_timespec (&repl->when, &server->params.values.period);
296         repl->amount = 1;
297
298         list_add_tail(&repl->repl_list,
299                        &server->replenishments.repl_list);
300
301         // check the new head
302         list_for_each(pos, &server->replenishments.repl_list) {
303                 repl = list_entry(pos, frescan_repl_op_t, repl_list);
304                 break;
305         }
306
307         clock_gettime (CLOCK_MONOTONIC, &now);
308
309         if (smaller_timespec(&now, &repl->when)) {
310                 server->current_priority = FRESCAN_BACKGROUND_PRIO;
311
312                 timerdata.it_interval.tv_sec  = 0;
313                 timerdata.it_interval.tv_nsec = 0;
314                 timerdata.it_value = repl->when;
315
316                 DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
317                       "set timer to %d sec, %d nsec\n",
318                       repl->when.tv_sec, repl->when.tv_nsec);
319
320                 ret = timer_settime(server->repl_timer,
321                                     TIMER_ABSTIME, &timerdata, NULL);
322                 if (ret != 0) {
323                         ERROR("could not set the replenishment timer\n");
324                         return ret;
325                 }
326         }
327
328 #if FRESCAN_MEASURE_REPL_PROGRAM
329                 ret = time_measure_posix_end(measure_id, "program");
330                 assert(ret == 0);
331
332                 while (logger_manual_call() > 0);
333 #endif
334
335         return 0;
336 }