]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_servers.c_posix
add get budget and period
[frescor/fna.git] / src_frescan / frescan_servers.c_posix
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 <misc/linux_list.h>
76 #include <misc/timespec_operations.h>
77 #include <signal.h>
78 #include <time.h>
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                 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 ret, pos;
122         struct sigevent evp;
123
124         FRESCAN_ACQUIRE_LOCK(&the_networks[net].lock);
125         pos = freelist_alloc(&the_servers_pool_freelist[net]);
126         FRESCAN_RELEASE_LOCK(&the_networks[net].lock);
127
128         if (pos == -1) {
129                 ERROR("could not allocate servers\n");
130                 return -1;
131         }
132
133         *id = (frescan_ss_t)pos;
134
135         the_servers_pool[net][*id].net = net;
136         the_servers_pool[net][*id].id  = *id;
137         the_servers_pool[net][*id].params = *params;
138         the_servers_pool[net][*id].current_budget = params->values.budget;
139         the_servers_pool[net][*id].current_priority = params->prio;
140         the_servers_pool[net][*id].pending_packets = 0;
141
142         // the first act_time is set to the server creation time
143         clock_gettime (CLOCK_MONOTONIC, &the_servers_pool[net][*id].act_time);
144
145         INIT_LIST_HEAD(&the_servers_pool[net][*id].replenishments.repl_list);
146         INIT_LIST_HEAD(&the_servers_pool[net][*id].packet_list.fifo_list);
147
148         // the repl timer sends a signal when it expires with the server id
149         evp.sigev_notify = SIGEV_SIGNAL;
150         evp.sigev_signo  = FRESCAN_REPL_SIGNAL_NUM;
151         evp.sigev_value.sival_int  = (int)*id;
152
153         ret = timer_create (CLOCK_MONOTONIC,
154                             &evp, &the_servers_pool[net][*id].repl_timer);
155         if (ret != 0) {
156                 ERROR("could not create timer\n");
157                 return ret;
158         }
159
160         DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
161               "server created, id:%u budget:%u prio:%u\n",
162               *id,
163               the_servers_pool[net][*id].params.values.budget,
164               the_servers_pool[net][*id].params.prio);
165
166         return 0;
167 }
168
169 /**
170  * frescan_servers_update() - update a sporadic server data
171  *
172  * @net: the network instance
173  * @params: the parameters for the server
174  * @id: the identificator for the server
175  *
176  */
177
178 int frescan_servers_update(frescan_network_t net,
179                            const frescan_server_params_t *params,
180                            frescan_ss_t id)
181 {
182         the_servers_pool[net][id].params = *params;
183         return 0;
184 }
185
186 /**
187  * frescan_servers_destroy() - delete a sporadic server
188  *
189  * @net: the network instance
190  * @id: the identificator for the server
191  *
192  */
193
194 int frescan_servers_destroy(frescan_network_t net, frescan_ss_t id)
195 {
196         int ret;
197
198         // TODO: free the replenishment operations and the packets for the
199         // server.
200
201         ret = timer_delete (the_servers_pool[net][id].repl_timer);
202         if (ret != 0) {
203                 ERROR("could not delete timer\n");
204                 return ret;
205         }
206
207         FRESCAN_ACQUIRE_LOCK(&the_networks[net].lock);
208         list_del(&the_servers_pool[net][id].servers_list);
209
210         ret = freelist_free(&the_servers_pool_freelist[net], id);
211         FRESCAN_RELEASE_LOCK(&the_networks[net].lock);
212         if (ret != 0) {
213                 ERROR("could not free server data from pool\n");
214                 return ret;
215         }
216
217         return 0;
218 }
219
220 /**
221  * frescan_servers_get_data() - get a sporadic server data
222  *
223  * @net: the network instance
224  * @params: the parameters of the server
225  * @id: the identificator for the server
226  *
227  */
228
229 int frescan_servers_get_data(frescan_network_t net,
230                              frescan_server_params_t *params,
231                              frescan_ss_t id)
232 {
233         *params = the_servers_pool[net][id].params;
234         return 0;
235 }
236
237 /**
238  * frescan_servers_get_current_budget() - get the current sporadic server budget
239  *
240  * @net: the network instance
241  * @id: the identificator for the server
242  * @current_budget: the current budget of the server
243  *
244  */
245
246 int frescan_servers_get_current_budget(frescan_network_t net,
247                                        frescan_ss_t id,
248                                        frescan_budget_t *current_budget)
249 {
250         *current_budget = the_servers_pool[net][id].current_budget;
251         return 0;
252 }
253
254 /**
255  * frescan_servers_get_highest_prio() - get the server with highest priority
256  *
257  * @net: the network instance
258  * @id: the identificator for the server
259  * @prio: the priority of that server
260  *
261  * For each active server, check the priority.
262  * If "id" is returned with a value of FRESCAN_MX_IDS,
263  * there are no active servers.
264  * NOTE: id=FRESCAN_MX_IDS is the identifier for fixed priority messages
265  * TODO: use a priority queue of active servers
266  *
267  */
268
269 int frescan_servers_get_highest_prio(frescan_network_t net,
270                                      frescan_ss_t *id,
271                                      frescan_prio_t *prio)
272 {
273         frescan_server_data_t *server;
274
275         if (list_empty(&the_active_servers->servers_list)) {
276                 DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "server list is empty\n");
277                 *id = FRESCAN_MX_IDS;
278                 return 0;
279         }
280
281         *prio = 0;
282         list_for_each_entry(server, &the_active_servers[net].servers_list,
283                             servers_list) {
284                 if (server->current_priority >= *prio) {
285                         *id = server->id;
286                         *prio = server->current_priority;
287                 }
288         }
289
290         DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
291               "highest prio:%u id:%u\n", *prio, *id);
292
293         return 0;
294 }
295
296 /**
297  * frescan_servers_frame_sent() - hook to control the server budget and prio
298  *
299  * @net: the network instance
300  * @id: the identificator for the server
301  *
302  * This function is called when a frame has been effectively sent through the
303  * CAN bus and that frame is associated to a certain server. The function
304  * decreases the capacity of the server and sets the priority to background
305  * in case the budget is exhausted.
306  *
307  * NOTE: the replenishment operation is programmed using the corresponding
308  * function at frescan_servers_replenishments module
309  */
310
311 int frescan_servers_frame_sent(frescan_network_t net,
312                                frescan_ss_t id,
313                                frescan_packet_t *packet)
314 {
315         int ret;
316         struct timespec *repl_time;
317         frescan_server_data_t *server;
318
319         server = &the_servers_pool[net][id];
320
321         DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
322               "before.. id:%u, current_budget:%u, current_priority:%u\n",
323               id, server->current_budget, server->current_priority);
324
325         if (server->current_budget > 0) {
326                 server->current_budget--;
327                 if (server->current_budget == 0) {
328                         server->current_priority = FRESCAN_BACKGROUND_PRIO;
329                 }
330
331                 if (smaller_timespec(&packet->timestamp, &server->act_time)) {
332                         DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "using act_time\n");
333                         repl_time = &server->act_time;
334                 } else {
335                         repl_time = &packet->timestamp;
336                 }
337
338                 ret = frescan_replenishment_program(net, id, repl_time);
339                 if (ret != 0) return -1;
340         }
341
342         DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
343               "after.. id:%u, current_budget:%u, current_priority:%u\n",
344               id, server->current_budget, server->current_priority);
345
346         return 0;
347 }