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