2 * @file frescan_queues.c
4 * @brief FRESCAN queues to manage the packets by prio and servers
15 * This file contains the FRESCAN queues where frescan packets are stored and
18 * TODO: disable interrupts for mutual exclusion!!!
22 //----------------------------------------------------------------------
23 // Copyright (C) 2006 - 2009 by the FRESCOR consortium:
25 // Universidad de Cantabria, SPAIN
26 // University of York, UK
27 // Scuola Superiore Sant'Anna, ITALY
28 // Kaiserslautern University, GERMANY
29 // Univ. Politecnica Valencia, SPAIN
30 // Czech Technical University in Prague, CZECH REPUBLIC
32 // Thales Communication S.A. FRANCE
33 // Visual Tools S.A. SPAIN
34 // Rapita Systems Ltd UK
37 // See http://www.frescor.org
39 // The FRESCOR project (FP6/2005/IST/5-034026) is funded
40 // in part by the European Union Sixth Framework Programme
41 // The European Union is not liable of any use that may be
45 // based on previous work (FSF) done in the FIRST project
47 // Copyright (C) 2005 Mälardalen University, SWEDEN
48 // Scuola Superiore S.Anna, ITALY
49 // Universidad de Cantabria, SPAIN
50 // University of York, UK
52 // This file is part of FNA (Frescor Network Adaptation)
54 // FNA is free software; you can redistribute it and/or modify it
55 // under terms of the GNU General Public License as published by the
56 // Free Software Foundation; either version 2, or (at your option) any
57 // later version. FNA is distributed in the hope that it will be
58 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
59 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
60 // General Public License for more details. You should have received a
61 // copy of the GNU General Public License along with FNA; see file
62 // COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,
63 // Cambridge, MA 02139, USA.
65 // As a special exception, including FNA header files in a file,
66 // instantiating FNA generics or templates, or linking other files
67 // with FNA objects to produce an executable application, does not
68 // by itself cause the resulting executable application to be covered
69 // by the GNU General Public License. This exception does not
70 // however invalidate any other reasons why the executable file might be
71 // covered by the GNU Public License.
72 // -----------------------------------------------------------------------
79 #include "frescan_queues.h"
80 #include "frescan_packets.h"
81 #include "frescan_debug.h"
82 #include "frescan_id.h"
83 #include "frescan_data.h"
86 * frescan_pqueue_create() - creates a priority queue
89 static inline frescan_prio_queue_t *frescan_pqueue_create(uint32_t max_prio,
90 frescan_network_t net)
93 frescan_prio_queue_t *pq; // priority queue
95 pq = (frescan_prio_queue_t *)malloc(sizeof(frescan_prio_queue_t));
97 FRESCAN_ERROR("could not allocate memory for prio queue\n");
101 pq->max_prio = max_prio;
104 ret = sem_init (&pq->sem, 0, 0);
106 FRESCAN_ERROR("could not init the semaphore\n");
111 pq->fifo_queues = (frescan_packet_t *)
112 malloc(max_prio * sizeof(frescan_packet_t));
114 for(prio=0; prio<max_prio; prio++) {
115 INIT_LIST_HEAD(&(pq->fifo_queues[prio].fifo_list));
122 * frescan_queues_init() - initialize the queues
124 * 1.- create the transmission fixed priority queue
125 * 2.- create the rx channels and its associated priority queues
127 * TODO: when error free memory
130 int frescan_queues_init(frescan_queues_t *queues,
131 frescan_init_params_t *params)
136 // create transmission fixed priority queue
137 queues->tx_fp_queue = frescan_pqueue_create(params->tx_fp_max_prio,
140 if (queues->tx_fp_queue == NULL) {
141 FRESCAN_ERROR("could not allocate memory for tx fp queue\n");
145 // create receiving channels
146 queues->rx_channel_queues = (frescan_prio_queue_t **)
147 malloc(params->rx_num_of_channels *
148 sizeof(frescan_prio_queue_t *));
150 if (queues->rx_channel_queues == NULL) {
152 ("could not allocate memory for receiving channels\n");
156 queues->num_rx_channels = params->rx_num_of_channels;
158 // create a priority queue for each channel
159 for(i=0; i<params->rx_num_of_channels; i++) {
161 if (params->rx_channel_max_prio == NULL) {
162 max_prio = params->tx_fp_max_prio;
164 max_prio = params->rx_channel_max_prio[i];
167 queues->rx_channel_queues[i] = frescan_pqueue_create
168 (max_prio, params->net);
170 if (queues->rx_channel_queues[i] == NULL) {
172 ("could not allocate memory for rx pq %d\n", i);
181 * frescan_pqueue_enqueue() - enqueue a packet
183 * check the packet flags and enqueue the packet in the appropiate queue
186 int frescan_pqueue_enqueue(frescan_prio_queue_t *pqueue,
187 frescan_packet_t *packet,
192 if (prio >= pqueue->max_prio) {
193 FRESCAN_ERROR("priority of the packet is too high\n");
197 DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG,
198 "enqueue packet with prio %u, pending %u\n",
199 prio, packet->buffer_pending_bytes);
201 list_add_tail(&(packet->fifo_list),
202 &(pqueue->fifo_queues[prio].fifo_list));
204 ret = sem_post(&pqueue->sem);
205 if (ret != 0) return ret;
211 * frescan_pqueue_requeue() - requeue a packet
214 int frescan_pqueue_requeue(frescan_prio_queue_t *pqueue,
215 frescan_packet_t *packet,
220 if (prio >= pqueue->max_prio) {
221 FRESCAN_ERROR("priority of the packet is too high\n");
225 list_add(&packet->fifo_list, &(pqueue->fifo_queues[prio].fifo_list));
227 ret = sem_post(&pqueue->sem);
228 if (ret != 0) return ret;
234 * frescan_pqueue_dequeue() - dequeue the packet with highest priority
237 int frescan_pqueue_dequeue(frescan_prio_queue_t *pqueue,
238 frescan_packet_t **packet,
239 frescan_prio_t *packet_prio,
244 frescan_packet_t *tmp = NULL;
245 struct list_head *pos;
250 DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG, "calling sem_wait\n");
251 sem_wait(&pqueue->sem);
253 ret = sem_trywait (&pqueue->sem);
255 DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG,
256 "sem_trywait was locked (no packets)\n");
261 DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG,
262 "check priority fifo queues (max_prio=%u)\n", pqueue->max_prio);
264 // NOTE: we only acquire the lock if we block because non-blocking
265 // calls are made from a context with no interrupts (when updating
266 // the buffer at 'frescan_hw_buffer_update' which is always called
267 // with interrupts disabled)
268 if (blocking) FRESCAN_ACQUIRE_LOCK(&frescan_data[pqueue->net].lock);
270 for(prio=pqueue->max_prio-1; prio >= 0; prio--) {
271 if (!list_empty(&pqueue->fifo_queues[prio].fifo_list)) {
273 &pqueue->fifo_queues[prio].fifo_list) {
274 tmp = list_entry(pos, frescan_packet_t,
279 list_del(&tmp->fifo_list);
284 if (blocking) FRESCAN_RELEASE_LOCK(&frescan_data[pqueue->net].lock);
286 DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG, "dequeued prio %u\n", prio);
293 * frescan_pqueue_get_highest_prio() - returns the packet with highest prio
294 * but not extracting it from the queue.
297 int frescan_pqueue_get_highest_prio(frescan_prio_queue_t *pqueue,
298 frescan_packet_t **packet,
299 frescan_prio_t *packet_prio)
302 frescan_packet_t *tmp = NULL;
303 struct list_head *pos;
307 for(prio=pqueue->max_prio-1; prio >= 0; prio--) {
308 if (!list_empty(&pqueue->fifo_queues[prio].fifo_list)) {
310 &pqueue->fifo_queues[prio].fifo_list) {
311 tmp = list_entry(pos, frescan_packet_t,
320 DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG, "highest prio %u\n", prio);
328 * frescan_servers_enqueue() - enqueue a packet through a server
330 * @net: the network instance
331 * @id: the identificator for the server
332 * @packet: the packet being enqueued
336 int frescan_servers_enqueue(frescan_network_t net,
338 frescan_packet_t *packet)
340 frescan_ss_data_t *server = &frescan_data[net].ss_data[id];
342 clock_gettime (CLOCK_MONOTONIC, &packet->timestamp);
344 DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "id:%u timestamp:(%d, %d)\n",
345 id, packet->timestamp.tv_sec, packet->timestamp.tv_nsec);
347 // add the packet to the server fifo list
348 list_add_tail(&packet->fifo_list, &server->packet_list.fifo_list);
350 // if the server was inactive (no packets) put it in the active list
351 if (server->pending_packets == 0) {
352 DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
353 "ss becomes active act_time=timestamp\n");
354 list_add_tail(&server->servers_list,
355 &frescan_data[net].ss_active_head.servers_list);
356 server->act_time = packet->timestamp;
359 server->pending_packets++;
364 * frescan_servers_requeue() - requeue a packet through a server
366 * @net: the network instance
367 * @id: the identificator for the server
368 * @packet: the packet being requeued
372 int frescan_servers_requeue(frescan_network_t net,
374 frescan_packet_t *packet)
376 DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
377 "requeue packet for id:%u\n", id);
379 // add the packet to the server fifo list
380 list_add(&packet->fifo_list,
381 &frescan_data[net].ss_data[id].packet_list.fifo_list);
383 // if the server was inactive (no packets to send) put it active
384 // (in the active list)
385 if (frescan_data[net].ss_data[id].pending_packets == 0) {
386 DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
387 "server was inactive, put in the active list\n");
388 list_add(&frescan_data[net].ss_data[id].servers_list,
389 &frescan_data[net].ss_active_head.servers_list);
392 frescan_data[net].ss_data[id].pending_packets++;
397 * frescan_servers_dequeue() - dequeue a packet from a server
399 * @net: the network instance
400 * @id: the identificator for the server
401 * @packet: the packet dequeued
402 * @packet_prio: the priority current of the server
406 int frescan_servers_dequeue(frescan_network_t net,
408 frescan_packet_t **packet,
409 frescan_prio_t *packet_prio)
411 struct list_head *pos;
412 frescan_ss_data_t *server;
414 server = &frescan_data[net].ss_data[id];
416 if (list_empty(&server->packet_list.fifo_list)) {
417 FRESCAN_ERROR("no packet in server %d fifo list\n", id);
421 list_for_each(pos, &server->packet_list.fifo_list) {
422 *packet = list_entry(pos, frescan_packet_t, fifo_list);
426 list_del(&((*packet)->fifo_list));
427 *packet_prio = server->current_priority;
428 server->pending_packets--;
430 if (server->pending_packets == 0) {
431 DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
432 "no more packets, delete from active list\n");
433 list_del(&server->servers_list);
436 DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
437 "dequeued packet server:%u cur_prio:%u pending:%u\n",
438 id, *packet_prio, server->pending_packets);