]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_servers.c
5f151b3d1bc6a0b82194159c2f5dbc923de537fd
[frescor/fna.git] / src_frescan / frescan_servers.c
1 /*!
2  * @file frescan_servers.c
3  *
4  * @brief FRESCAN sporadic servers
5  *
6  * @version 0.01
7  *
8  * @date 27-Feb-2008
9  *
10  * @author
11  *      Daniel Sangorrin
12  *
13  * @comments
14  *
15  * This file contains the FRESCAN sporadic servers that allow to isolate
16  * different streams of data by assigning them a budget and replenishment
17  * period.
18  *
19  * @license
20  *
21  * -----------------------------------------------------------------------
22  *  Copyright (C) 2006 - 2008 FRESCOR consortium partners:
23  *
24  *    Universidad de Cantabria,              SPAIN
25  *    University of York,                    UK
26  *    Scuola Superiore Sant'Anna,            ITALY
27  *    Kaiserslautern University,             GERMANY
28  *    Univ. Politécnica  Valencia,           SPAIN
29  *    Czech Technical University in Prague,  CZECH REPUBLIC
30  *    ENEA                                   SWEDEN
31  *    Thales Communication S.A.              FRANCE
32  *    Visual Tools S.A.                      SPAIN
33  *    Rapita Systems Ltd                     UK
34  *    Evidence                               ITALY
35  *
36  *    See http://www.frescor.org for a link to partners' websites
37  *
38  *           FRESCOR project (FP6/2005/IST/5-034026) is funded
39  *        in part by the European Union Sixth Framework Programme
40  *        The European Union is not liable of any use that may be
41  *        made of this code.
42  *
43  *  This file is part of FRESCAN
44  *
45  *  FRESCAN is free software; you can  redistribute it and/or  modify
46  *  it under the terms of  the GNU General Public License as published by
47  *  the Free Software Foundation;  either  version 2, or (at  your option)
48  *  any later version.
49  *
50  *  FRESCAN  is distributed  in  the hope  that  it  will  be useful,  but
51  *  WITHOUT  ANY  WARRANTY;     without  even the   implied   warranty  of
52  *  MERCHANTABILITY  or  FITNESS FOR  A  PARTICULAR PURPOSE. See  the  GNU
53  *  General Public License for more details.
54  *
55  *  You should have  received a  copy of  the  GNU  General Public License
56  *  distributed  with  FRESCAN;  see file COPYING.   If not,  write to the
57  *  Free Software  Foundation,  59 Temple Place  -  Suite 330,  Boston, MA
58  *  02111-1307, USA.
59  *
60  * As a special exception, including FRESCAN header files in a file,
61  * instantiating FRESCAN generics or templates, or linking other files
62  * with FRESCAN objects to produce an executable application, does not
63  * by itself cause the resulting executable application to be covered
64  * by the GNU General Public License. This exception does not
65  * however invalidate any other reasons why the executable file might be
66  * covered by the GNU Public License.
67  * -----------------------------------------------------------------------
68  *
69  */
70
71 #include "frescan_servers.h"
72 #include "frescan_servers_replenishments.h" // frescan_replenishments_xxx
73 #include "frescan_debug.h"
74 #include "frescan_data.h"
75 #include <signal.h>
76 #include <time.h>
77 #include <misc/linux_list.h>
78 #include "fosa_time_timespec.h" // smaller_timespec
79
80 /**
81  * frescan_servers_init() - initialize server structures
82  *
83  * @net: the network instance
84  */
85
86 int frescan_servers_init(frescan_network_t net)
87 {
88         int ret, i;
89
90         DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "initializing servers\n");
91
92         ret = freelist_init(&the_servers_pool_freelist[net], FRESCAN_MX_IDS);
93         if (ret != 0) return ret;
94
95         for (i=0; i<FRESCAN_MX_NETWORKS; i++) {
96                 INIT_LIST_HEAD(&the_active_servers[net].servers_list);
97         }
98
99         ret = frescan_replenishments_init(net);
100         if (ret != 0) {
101                 FRESCAN_ERROR("could not initialize the replenishments\n");
102                 return -1;
103         }
104
105         return 0;
106 }
107
108 /**
109  * frescan_servers_create() - create a sporadic server
110  *
111  * @net: the network instance
112  * @params: the parameters for the server
113  * @id: the identificator for the server as a return value
114  *
115  */
116
117 int frescan_servers_create(frescan_network_t net,
118                            const frescan_server_params_t *params,
119                            frescan_ss_t *id)
120 {
121         int i, ret, pos;
122         struct sigevent evp;
123         frescan_server_data_t *server;
124         frescan_repl_op_t *repl;
125
126         FRESCAN_ACQUIRE_LOCK(&the_networks[net].lock);
127         pos = freelist_alloc(&the_servers_pool_freelist[net]);
128         FRESCAN_RELEASE_LOCK(&the_networks[net].lock);
129
130         if (pos == -1) {
131                 FRESCAN_ERROR("could not allocate servers\n");
132                 return -1;
133         }
134
135         *id = (frescan_ss_t)pos;
136
137         server = &the_servers_pool[net][*id];
138
139         server->net = net;
140         server->id  = *id;
141         server->params = *params;
142         server->current_priority = params->prio;
143         server->pending_packets = 0;
144
145         // the first act_time is set to the server creation time
146         clock_gettime (CLOCK_MONOTONIC, &server->act_time);
147
148         // init the list of packets associated to the server
149         INIT_LIST_HEAD(&server->packet_list.fifo_list);
150
151         // allocate the replenishment capacity queue
152         INIT_LIST_HEAD(&server->replenishments.repl_list);
153         for (i=0; i < params->budget; i++) {
154                 repl = frescan_repl_op_alloc();
155                 repl->when = server->act_time;
156                 repl->amount = 1;
157                 list_add_tail(&repl->repl_list,
158                               &server->replenishments.repl_list);
159         }
160
161         // the repl timer sends a signal when it expires with the server id
162         evp.sigev_notify = SIGEV_SIGNAL;
163         evp.sigev_signo  = FRESCAN_REPL_SIGNAL_NUM;
164         evp.sigev_value.sival_int  = (int)*id;
165
166         ret = timer_create (CLOCK_MONOTONIC, &evp, &server->repl_timer);
167         if (ret != 0) {
168                 FRESCAN_ERROR("could not create timer\n");
169                 return ret;
170         }
171
172         DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
173               "server created, id:%u budget:%u prio:%u\n",
174               *id, server->params.budget, server->params.prio);
175
176         return 0;
177 }
178
179 /**
180  * frescan_servers_set_perceived() - update a sporadic server perceived data
181  *
182  * @net: the network instance
183  * @params: the parameters for the server
184  * @id: the identificator for the server
185  *
186  */
187
188 int frescan_servers_set_perceived(frescan_network_t net,
189                                   const frescan_server_params_t *params,
190                                   frescan_ss_t id)
191 {
192         frescan_server_data_t *server;
193
194         server = &the_servers_pool[net][id];
195
196         server->old_params = server->params;
197         server->params = *params;
198
199         return 0;
200 }
201
202 /**
203  * frescan_servers_commit_perceived() - commit sporadic server perceived data
204  *
205  * Add or remove repl operations according to the budget change
206  *
207  * @net: the network instance
208  * @id: the identificator for the server
209  *
210  */
211
212 int frescan_servers_commit_perceived(frescan_network_t net,
213                                      frescan_ss_t id)
214 {
215         int i, ret;
216         frescan_server_data_t *server;
217         int budget_variation;
218         frescan_repl_op_t *repl;
219         struct list_head *pos;
220
221         server = &the_servers_pool[net][id];
222         budget_variation = server->params.budget - server->old_params.budget;
223
224         if (budget_variation > 0) {
225                 // we have more budget: add repl ops to the tail
226                 for (i=0; i < budget_variation; i++) {
227                         repl = frescan_repl_op_alloc();
228                         repl->when = server->act_time; // TODO: check when!
229                         repl->amount = 1;
230                         list_add_tail(&repl->repl_list,
231                                       &server->replenishments.repl_list);
232                 }
233         } else {
234                 // we have less budget: remove repl ops from the tail
235                 for (i=0; i > budget_variation; i--) {
236                         list_for_each_prev(pos,
237                                            &server->replenishments.repl_list) {
238                                 repl = list_entry(pos,
239                                                   frescan_repl_op_t,
240                                                   repl_list);
241                                 break;
242                         }
243                         list_del(&repl->repl_list);
244
245                         ret = frescan_repl_op_free(repl);
246                         if (ret != 0) return ret;
247                 }
248         }
249
250         return 0;
251 }
252
253 /**
254  * frescan_servers_update() - update a sporadic server data
255  *
256  * @net: the network instance
257  * @params: the parameters for the server
258  * @id: the identificator for the server
259  *
260  */
261
262 int frescan_servers_update(frescan_network_t net,
263                            const frescan_server_params_t *params,
264                            frescan_ss_t id)
265 {
266         int ret;
267
268         ret = frescan_servers_set_perceived(net, params, id);
269         if (ret != 0) return ret;
270
271         ret = frescan_servers_commit_perceived(net, id);
272         if (ret != 0) return ret;
273
274         return 0;
275 }
276
277 /**
278  * frescan_servers_destroy() - delete a sporadic server
279  *
280  * @net: the network instance
281  * @id: the identificator for the server
282  *
283  */
284
285 int frescan_servers_destroy(frescan_network_t net, frescan_ss_t id)
286 {
287         int ret;
288         frescan_repl_op_t *repl;
289         frescan_packet_t *packet;
290         frescan_server_data_t *server;
291
292         server = &the_servers_pool[net][id];
293
294         ret = timer_delete (server->repl_timer);
295         if (ret != 0) {
296                 FRESCAN_ERROR("could not delete timer\n");
297                 return ret;
298         }
299
300         // remove packets associated to the server
301         if (!list_empty(&server->packet_list.fifo_list)) {
302                 FRESCAN_WARNING("destroying a server with packets enqueued\n");
303                 list_for_each_entry(packet,
304                                     &server->packet_list.fifo_list,
305                                     fifo_list) {
306                         ret = frescan_packets_free(packet);
307                         if (ret != 0) return ret;
308                 }
309                 INIT_LIST_HEAD(&server->packet_list.fifo_list);
310         }
311
312         // remove the servers replenishment capacity queue
313         list_for_each_entry(repl,
314                             &server->replenishments.repl_list,
315                             repl_list) {
316                 ret = frescan_repl_op_free(repl);
317                 if (ret != 0) return ret;
318         }
319         INIT_LIST_HEAD(&server->replenishments.repl_list);
320
321         FRESCAN_ACQUIRE_LOCK(&the_networks[net].lock);
322         list_del(&server->servers_list);
323         ret = freelist_free(&the_servers_pool_freelist[net], id);
324         FRESCAN_RELEASE_LOCK(&the_networks[net].lock);
325
326         if (ret != 0) {
327                 FRESCAN_ERROR("could not free server data from pool\n");
328                 return ret;
329         }
330
331         return 0;
332 }
333
334 /**
335  * frescan_servers_get_data() - get a sporadic server data
336  *
337  * @net: the network instance
338  * @params: the parameters of the server
339  * @id: the identificator for the server
340  *
341  */
342
343 int frescan_servers_get_data(frescan_network_t net,
344                              frescan_server_params_t *params,
345                              frescan_ss_t id)
346 {
347         *params = the_servers_pool[net][id].params;
348         return 0;
349 }
350
351 /**
352  * frescan_servers_get_current_budget() - get the current ss budget
353  *
354  * @net: the network instance
355  * @id: the identificator for the server
356  * @current_budget: the current budget of the server
357  *
358  * Traverse the capacity queue until we find a replenishment operation
359  * that was programmed for a time later than now.
360  *
361  */
362
363 int frescan_servers_get_current_budget(frescan_network_t net,
364                                        frescan_ss_t id,
365                                        frescan_budget_t *current_budget)
366 {
367         struct timespec now;
368         frescan_repl_op_t *repl;
369         frescan_server_data_t *server;
370
371         server = &the_servers_pool[net][id];
372
373         clock_gettime (CLOCK_MONOTONIC, &now);
374
375         *current_budget = 0;
376
377         list_for_each_entry(repl,
378                             &server->replenishments.repl_list,
379                             repl_list) {
380                 if (smaller_timespec(now, repl->when)) break;
381                 *current_budget = *current_budget + 1;
382         }
383
384         return 0;
385 }
386
387 /**
388  * frescan_servers_get_highest_prio() - get the server with highest priority
389  *
390  * @net: the network instance
391  * @id: the identificator for the server
392  * @prio: the priority of that server
393  *
394  * For each active server, check the priority.
395  * If "id" is returned with a value of FRESCAN_MX_IDS,
396  * there are no active servers.
397  * NOTE: id=FRESCAN_MX_IDS is the identifier for fixed priority messages
398  * TODO: use a priority queue of active servers
399  *
400  */
401
402 int frescan_servers_get_highest_prio(frescan_network_t net,
403                                      frescan_ss_t *id,
404                                      frescan_prio_t *prio)
405 {
406         frescan_server_data_t *server;
407
408         if (list_empty(&the_active_servers->servers_list)) {
409                 DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "server list is empty\n");
410                 *id = FRESCAN_MX_IDS;
411                 return 0;
412         }
413
414         *prio = 0;
415         list_for_each_entry(server, &the_active_servers[net].servers_list,
416                             servers_list) {
417                 if (server->current_priority >= *prio) {
418                         *id = server->id;
419                         *prio = server->current_priority;
420                 }
421         }
422
423         DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
424               "highest prio:%u id:%u\n", *prio, *id);
425
426         return 0;
427 }
428
429 /**
430  * frescan_servers_frame_sent() - hook to control the server budget and prio
431  *
432  * @net: the network instance
433  * @id: the identificator for the server
434  *
435  * This function is called when a frame has been effectively sent through the
436  * CAN bus and that frame is associated to a certain server. The function
437  * decreases the capacity of the server and sets the priority to background
438  * in case the budget is exhausted.
439  *
440  * NOTE: the replenishment operation is programmed using the corresponding
441  * function at frescan_servers_replenishments module
442  */
443
444 int frescan_servers_frame_sent(frescan_network_t net,
445                                frescan_ss_t id,
446                                frescan_packet_t *packet)
447 {
448         int ret;
449         struct timespec *repl_time;
450         frescan_server_data_t *server;
451
452         server = &the_servers_pool[net][id];
453
454         if (server->current_priority != FRESCAN_BACKGROUND_PRIO) {
455                 if (smaller_timespec(packet->timestamp, server->act_time)) {
456                         repl_time = &server->act_time;
457                 } else {
458                         repl_time = &packet->timestamp;
459                 }
460
461                 ret = frescan_replenishment_program(net, id, repl_time);
462                 if (ret != 0) return -1;
463         }
464
465         return 0;
466 }