#include "frescan_id.h" // frescan_id_set_field, frescan_id_get_field
#include "frescan_hw_buffer.h" // frescan_hw_buffer_update
#include "frescan_bwres_robjs.h" // frescan_replyobjects_init
-#include "frescan_servers_replenishments.h" // frescan_replenishments_xxx
#include "frescan_packets.h"
static int frescan_hook_frame_recv (const struct can_chip_t *chip,
return -1;
}
- ret = frescan_replenishments_init(params->net);
- if (ret != 0) {
- ERROR("could not initialize the replenishments\n");
- return -1;
- }
-
return 0;
}
DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
"calling frame_sent + program repl for id:%u\n", id);
- ret = frescan_replenishment_program(chip->minor,
- id,
- &packet->timestamp);
- if (ret != 0) {
- ERROR("could not program replenishment\n");
- return -1;
- }
-
- ret = frescan_servers_frame_sent(chip->minor, id);
+ ret = frescan_servers_frame_sent(chip->minor, id, packet);
if (ret != 0) {
ERROR("could not let the server a frame was sent\n");
return -1;
#include "frescan.h" // frescan_node_t, _prio_t, _budget_t
#include "frescan_config.h" // FRESCAN_MLOCK_T, FRESCAN_MX_XXX
#include "frescan_packets.h" // frescan_packet_t
-#include "frescan_servers_replenishments.h" // frescan_repl_op_t
/**
* frescan_repl_op_t - a replenishment operation
* @repl_list: the list of pending replenishment operations
* @repl_timer: the timer for the replenishments associated to this server
* NOTE: we could use a single timer for all but for now this is simpler
+ * @act_time: the last activation time for the server
* @packet_list: the packets enqueued on this server
+ * @servers_list: the list of servers
*/
typedef struct {
frescan_budget_t pending_packets;
frescan_repl_op_t replenishments;
timer_t repl_timer;
+ struct timespec act_time;
frescan_packet_t packet_list;
struct list_head servers_list;
} frescan_server_data_t;
* DEBUGGING FLAGS to enable/disable debugging messages
**/
-#define FRESCAN_SERVERS_ENABLE_DEBUG false
+#define FRESCAN_SERVERS_ENABLE_DEBUG true
#define FRESCAN_PACKETPOOL_ENABLE_DEBUG false
#define FRESCAN_FRAG_ENABLE_DEBUG false
#define FRESCAN_INIT_ENABLE_DEBUG false
#define FRESCAN_SENT_HOOK_ENABLE_DEBUG false
#define FRESCAN_QUEUES_ENABLE_DEBUG false
#define FRESCAN_HW_BUFFER_ENABLE_DEBUG false
-#define FRESCAN_REPLENSH_ENABLE_DEBUG false
+#define FRESCAN_REPLENSH_ENABLE_DEBUG true
#define FRESCAN_ROBJS_ENABLE_DEBUG false
-#define FRESCAN_BWRES_ENABLE_DEBUG true
+#define FRESCAN_BWRES_ENABLE_DEBUG false
#define FRESCAN_REQUESTS_ENABLE_DEBUG false
-#define FRESCAN_MANAGER_ENABLE_DEBUG true
-#define FRESCAN_ACCEPTOR_ENABLE_DEBUG true
+#define FRESCAN_MANAGER_ENABLE_DEBUG false
+#define FRESCAN_ACCEPTOR_ENABLE_DEBUG false
#define FRESCAN_FNA_ENABLE_DEBUG false
#define FRESCAN_MESSAGES_ENABLE_DEBUG false
#include <stdlib.h>
#include <time.h>
+#include <misc/timespec_operations.h>
#include "frescan_queues.h"
#include "frescan_packets.h"
frescan_ss_t id,
frescan_packet_t *packet)
{
- DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "enqueue packet for id:%u\n", id);
+ frescan_server_data_t *server = &the_servers_pool[net][id];
clock_gettime (CLOCK_MONOTONIC, &packet->timestamp);
+ DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "id:%u timestamp:(%d, %d)\n",
+ id, packet->timestamp.tv_sec, packet->timestamp.tv_nsec);
+
// add the packet to the server fifo list
- list_add_tail(&packet->fifo_list,
- &the_servers_pool[net][id].packet_list.fifo_list);
+ list_add_tail(&packet->fifo_list, &server->packet_list.fifo_list);
- // if the server was inactive (no packets to send) put it active
- // (in the active list)
- if (the_servers_pool[net][id].pending_packets == 0) {
+ // if the server was inactive (no packets) put it in the active list
+ if (server->pending_packets == 0) {
DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
- "server was inactive, put in the active list\n");
- list_add_tail(&the_servers_pool[net][id].servers_list,
- &the_active_servers[net].servers_list);
+ "ss becomes active act_time=timestamp\n");
+ list_add_tail(&server->servers_list,
+ &the_active_servers[net].servers_list);
+ server->act_time = packet->timestamp;
}
- the_servers_pool[net][id].pending_packets++;
+ server->pending_packets++;
return 0;
}
frescan_prio_t *packet_prio)
{
struct list_head *pos;
+ frescan_server_data_t *server;
- if (list_empty(&the_servers_pool[net][id].packet_list.fifo_list)) {
+ server = &the_servers_pool[net][id];
+
+ if (list_empty(&server->packet_list.fifo_list)) {
ERROR("no packet in server %d fifo list\n", id);
return -1;
}
- list_for_each(pos, &the_servers_pool[net][id].packet_list.fifo_list) {
+ list_for_each(pos, &server->packet_list.fifo_list) {
*packet = list_entry(pos, frescan_packet_t, fifo_list);
break;
}
list_del(&((*packet)->fifo_list));
- *packet_prio = the_servers_pool[net][id].current_priority;
- the_servers_pool[net][id].pending_packets--;
+ *packet_prio = server->current_priority;
+ server->pending_packets--;
- if (the_servers_pool[net][id].pending_packets == 0) {
+ if (server->pending_packets == 0) {
DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
"no more packets, delete from active list\n");
- list_del(&the_servers_pool[net][id].servers_list);
+ list_del(&server->servers_list);
}
DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
"dequeued packet server:%u cur_prio:%u pending:%u\n",
- id, *packet_prio, the_servers_pool[net][id].pending_packets);
+ id, *packet_prio, server->pending_packets);
return 0;
}
*/
#include "frescan_servers.h"
+#include "frescan_servers_replenishments.h" // frescan_replenishments_xxx
#include "frescan_debug.h"
#include "frescan_data.h"
#include <misc/linux_list.h>
+#include <misc/timespec_operations.h>
#include <signal.h>
+#include <time.h>
/**
* frescan_servers_init() - initialize server structures
INIT_LIST_HEAD(&the_active_servers[net].servers_list);
}
+ ret = frescan_replenishments_init(net);
+ if (ret != 0) {
+ ERROR("could not initialize the replenishments\n");
+ return -1;
+ }
+
return 0;
}
const frescan_server_params_t *params,
frescan_ss_t *id)
{
- int ret, pos;
+ int i, ret, pos;
struct sigevent evp;
+ frescan_server_data_t *server;
+ frescan_repl_op_t *repl;
FRESCAN_ACQUIRE_LOCK(&the_networks[net].lock);
pos = freelist_alloc(&the_servers_pool_freelist[net]);
*id = (frescan_ss_t)pos;
- the_servers_pool[net][*id].net = net;
- the_servers_pool[net][*id].id = *id;
- the_servers_pool[net][*id].params = *params;
- the_servers_pool[net][*id].current_budget = params->values.budget;
- the_servers_pool[net][*id].current_priority = params->prio;
- the_servers_pool[net][*id].pending_packets = 0;
-
- INIT_LIST_HEAD(&the_servers_pool[net][*id].replenishments.repl_list);
- INIT_LIST_HEAD(&the_servers_pool[net][*id].packet_list.fifo_list);
+ server = &the_servers_pool[net][*id];
+
+ server->net = net;
+ server->id = *id;
+ server->params = *params;
+ server->current_budget = params->values.budget;
+ server->current_priority = params->prio;
+ server->pending_packets = 0;
+
+ // the first act_time is set to the server creation time
+ clock_gettime (CLOCK_MONOTONIC, &server->act_time);
+
+ // init the list of packets associated to the server
+ INIT_LIST_HEAD(&server->packet_list.fifo_list);
+
+ // allocate the replenishment capacity queue
+ INIT_LIST_HEAD(&server->replenishments.repl_list);
+ for (i=0; i < params->values.budget; i++) {
+ repl = frescan_repl_op_alloc();
+ repl->when = server->act_time;
+ repl->amount = 1;
+ list_add_tail(&repl->repl_list,
+ &server->replenishments.repl_list);
+ }
// the repl timer sends a signal when it expires with the server id
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = FRESCAN_REPL_SIGNAL_NUM;
evp.sigev_value.sival_int = (int)*id;
- ret = timer_create (CLOCK_MONOTONIC,
- &evp, &the_servers_pool[net][*id].repl_timer);
+ ret = timer_create (CLOCK_MONOTONIC, &evp, &server->repl_timer);
if (ret != 0) {
ERROR("could not create timer\n");
return ret;
DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
"server created, id:%u budget:%u prio:%u\n",
- *id,
- the_servers_pool[net][*id].params.values.budget,
- the_servers_pool[net][*id].params.prio);
+ *id, server->params.values.budget, server->params.prio);
return 0;
}
* function at frescan_servers_replenishments module
*/
-int frescan_servers_frame_sent(frescan_network_t net, frescan_ss_t id)
+int frescan_servers_frame_sent(frescan_network_t net,
+ frescan_ss_t id,
+ frescan_packet_t *packet)
{
- DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
- "id:%u, current_budget:%u, current_priority:%u\n",
- id,
- the_servers_pool[net][id].current_budget,
- the_servers_pool[net][id].current_priority);
-
- if (the_servers_pool[net][id].current_budget > 0) {
- the_servers_pool[net][id].current_budget--;
- if (the_servers_pool[net][id].current_budget == 0) {
- the_servers_pool[net][id].current_priority =
- FRESCAN_BACKGROUND_PRIO;
+ int ret;
+ struct timespec *repl_time;
+ frescan_server_data_t *server;
+
+ server = &the_servers_pool[net][id];
+
+ if (server->current_priority != FRESCAN_BACKGROUND_PRIO) {
+ if (smaller_timespec(&packet->timestamp, &server->act_time)) {
+ repl_time = &server->act_time;
+ } else {
+ repl_time = &packet->timestamp;
}
+ ret = frescan_replenishment_program(net, id, repl_time);
+ if (ret != 0) return -1;
}
- DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
- "now... id:%u, current_budget:%u, current_priority:%u\n",
- id,
- the_servers_pool[net][id].current_budget,
- the_servers_pool[net][id].current_priority);
-
return 0;
}
--- /dev/null
+/*!
+ * @file frescan_servers.c
+ *
+ * @brief FRESCAN sporadic servers
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ * Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the FRESCAN sporadic servers that allow to isolate
+ * different streams of data by assigning them a budget and replenishment
+ * period.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include "frescan_servers.h"
+#include "frescan_servers_replenishments.h" // frescan_replenishments_xxx
+#include "frescan_debug.h"
+#include "frescan_data.h"
+#include <misc/linux_list.h>
+#include <misc/timespec_operations.h>
+#include <signal.h>
+#include <time.h>
+
+/**
+ * frescan_servers_init() - initialize server structures
+ *
+ * @net: the network instance
+ */
+
+int frescan_servers_init(frescan_network_t net)
+{
+ int ret, i;
+
+ DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "initializing servers\n");
+
+ ret = freelist_init(&the_servers_pool_freelist[net], FRESCAN_MX_IDS);
+ if (ret != 0) return ret;
+
+ for (i=0; i<FRESCAN_MX_NETWORKS; i++) {
+ INIT_LIST_HEAD(&the_active_servers[net].servers_list);
+ }
+
+ ret = frescan_replenishments_init(net);
+ if (ret != 0) {
+ ERROR("could not initialize the replenishments\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * frescan_servers_create() - create a sporadic server
+ *
+ * @net: the network instance
+ * @params: the parameters for the server
+ * @id: the identificator for the server as a return value
+ *
+ */
+
+int frescan_servers_create(frescan_network_t net,
+ const frescan_server_params_t *params,
+ frescan_ss_t *id)
+{
+ int ret, pos;
+ struct sigevent evp;
+
+ FRESCAN_ACQUIRE_LOCK(&the_networks[net].lock);
+ pos = freelist_alloc(&the_servers_pool_freelist[net]);
+ FRESCAN_RELEASE_LOCK(&the_networks[net].lock);
+
+ if (pos == -1) {
+ ERROR("could not allocate servers\n");
+ return -1;
+ }
+
+ *id = (frescan_ss_t)pos;
+
+ the_servers_pool[net][*id].net = net;
+ the_servers_pool[net][*id].id = *id;
+ the_servers_pool[net][*id].params = *params;
+ the_servers_pool[net][*id].current_budget = params->values.budget;
+ the_servers_pool[net][*id].current_priority = params->prio;
+ the_servers_pool[net][*id].pending_packets = 0;
+
+ // the first act_time is set to the server creation time
+ clock_gettime (CLOCK_MONOTONIC, &the_servers_pool[net][*id].act_time);
+
+ INIT_LIST_HEAD(&the_servers_pool[net][*id].replenishments.repl_list);
+ INIT_LIST_HEAD(&the_servers_pool[net][*id].packet_list.fifo_list);
+
+ // the repl timer sends a signal when it expires with the server id
+ evp.sigev_notify = SIGEV_SIGNAL;
+ evp.sigev_signo = FRESCAN_REPL_SIGNAL_NUM;
+ evp.sigev_value.sival_int = (int)*id;
+
+ ret = timer_create (CLOCK_MONOTONIC,
+ &evp, &the_servers_pool[net][*id].repl_timer);
+ if (ret != 0) {
+ ERROR("could not create timer\n");
+ return ret;
+ }
+
+ DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+ "server created, id:%u budget:%u prio:%u\n",
+ *id,
+ the_servers_pool[net][*id].params.values.budget,
+ the_servers_pool[net][*id].params.prio);
+
+ return 0;
+}
+
+/**
+ * frescan_servers_update() - update a sporadic server data
+ *
+ * @net: the network instance
+ * @params: the parameters for the server
+ * @id: the identificator for the server
+ *
+ */
+
+int frescan_servers_update(frescan_network_t net,
+ const frescan_server_params_t *params,
+ frescan_ss_t id)
+{
+ the_servers_pool[net][id].params = *params;
+ return 0;
+}
+
+/**
+ * frescan_servers_destroy() - delete a sporadic server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ *
+ */
+
+int frescan_servers_destroy(frescan_network_t net, frescan_ss_t id)
+{
+ int ret;
+
+ // TODO: free the replenishment operations and the packets for the
+ // server.
+
+ ret = timer_delete (the_servers_pool[net][id].repl_timer);
+ if (ret != 0) {
+ ERROR("could not delete timer\n");
+ return ret;
+ }
+
+ FRESCAN_ACQUIRE_LOCK(&the_networks[net].lock);
+ list_del(&the_servers_pool[net][id].servers_list);
+
+ ret = freelist_free(&the_servers_pool_freelist[net], id);
+ FRESCAN_RELEASE_LOCK(&the_networks[net].lock);
+ if (ret != 0) {
+ ERROR("could not free server data from pool\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * frescan_servers_get_data() - get a sporadic server data
+ *
+ * @net: the network instance
+ * @params: the parameters of the server
+ * @id: the identificator for the server
+ *
+ */
+
+int frescan_servers_get_data(frescan_network_t net,
+ frescan_server_params_t *params,
+ frescan_ss_t id)
+{
+ *params = the_servers_pool[net][id].params;
+ return 0;
+}
+
+/**
+ * frescan_servers_get_current_budget() - get the current sporadic server budget
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @current_budget: the current budget of the server
+ *
+ */
+
+int frescan_servers_get_current_budget(frescan_network_t net,
+ frescan_ss_t id,
+ frescan_budget_t *current_budget)
+{
+ *current_budget = the_servers_pool[net][id].current_budget;
+ return 0;
+}
+
+/**
+ * frescan_servers_get_highest_prio() - get the server with highest priority
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @prio: the priority of that server
+ *
+ * For each active server, check the priority.
+ * If "id" is returned with a value of FRESCAN_MX_IDS,
+ * there are no active servers.
+ * NOTE: id=FRESCAN_MX_IDS is the identifier for fixed priority messages
+ * TODO: use a priority queue of active servers
+ *
+ */
+
+int frescan_servers_get_highest_prio(frescan_network_t net,
+ frescan_ss_t *id,
+ frescan_prio_t *prio)
+{
+ frescan_server_data_t *server;
+
+ if (list_empty(&the_active_servers->servers_list)) {
+ DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "server list is empty\n");
+ *id = FRESCAN_MX_IDS;
+ return 0;
+ }
+
+ *prio = 0;
+ list_for_each_entry(server, &the_active_servers[net].servers_list,
+ servers_list) {
+ if (server->current_priority >= *prio) {
+ *id = server->id;
+ *prio = server->current_priority;
+ }
+ }
+
+ DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+ "highest prio:%u id:%u\n", *prio, *id);
+
+ return 0;
+}
+
+/**
+ * frescan_servers_frame_sent() - hook to control the server budget and prio
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ *
+ * This function is called when a frame has been effectively sent through the
+ * CAN bus and that frame is associated to a certain server. The function
+ * decreases the capacity of the server and sets the priority to background
+ * in case the budget is exhausted.
+ *
+ * NOTE: the replenishment operation is programmed using the corresponding
+ * function at frescan_servers_replenishments module
+ */
+
+int frescan_servers_frame_sent(frescan_network_t net,
+ frescan_ss_t id,
+ frescan_packet_t *packet)
+{
+ int ret;
+ struct timespec *repl_time;
+ frescan_server_data_t *server;
+
+ server = &the_servers_pool[net][id];
+
+ DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+ "before.. id:%u, current_budget:%u, current_priority:%u\n",
+ id, server->current_budget, server->current_priority);
+
+ if (server->current_budget > 0) {
+ server->current_budget--;
+ if (server->current_budget == 0) {
+ server->current_priority = FRESCAN_BACKGROUND_PRIO;
+ }
+
+ if (smaller_timespec(&packet->timestamp, &server->act_time)) {
+ DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "using act_time\n");
+ repl_time = &server->act_time;
+ } else {
+ repl_time = &packet->timestamp;
+ }
+
+ ret = frescan_replenishment_program(net, id, repl_time);
+ if (ret != 0) return -1;
+ }
+
+ DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+ "after.. id:%u, current_budget:%u, current_priority:%u\n",
+ id, server->current_budget, server->current_priority);
+
+ return 0;
+}
*
* @net: the network instance
* @id: the identificator for the server
+ * @packet: the packet sent (with its timestamp)
*
* This function is called when a frame has been effectively sent through the
* CAN bus and that frame is associated to a certain server. The function
* function at frescan_servers_replenishments module
*/
-extern int frescan_servers_frame_sent(frescan_network_t net, frescan_ss_t id);
+extern int frescan_servers_frame_sent(frescan_network_t net,
+ frescan_ss_t id,
+ frescan_packet_t *packet);
#endif // _MARTE_FRESCAN_SERVERS_H_
return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
}
-static frescan_repl_op_t *frescan_repl_op_alloc()
+frescan_repl_op_t *frescan_repl_op_alloc()
{
int pos;
return &the_repl_op_pool[pos];
}
-static int frescan_repl_op_free(frescan_repl_op_t *repl_op)
+int frescan_repl_op_free(frescan_repl_op_t *repl_op)
{
return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
}
siginfo_t siginfo;
frescan_ss_t id;
frescan_network_t net;
- struct list_head *pos;
- frescan_repl_op_t *repl = NULL;
frescan_server_data_t *server;
struct itimerspec timerdata;
server = &the_servers_pool[net][id];
DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
- "id:%u, current_budget:%u, budget:%u, current_prio:%u\n",
- id,
- server->current_budget,
- server->params.values.budget,
- server->current_priority);
-
- server->current_budget++;
-
- if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
- server->current_priority = server->params.prio;
- }
-
- DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
- "now... current_budget:%u, current_prio:%u\n",
- server->current_budget,
- server->current_priority);
-
- // delete the replenishment of this call
- list_for_each(pos, &server->replenishments.repl_list) {
- repl = list_entry(pos, frescan_repl_op_t, repl_list);
- break;
- }
-
- list_del(&repl->repl_list);
-
- ret = frescan_repl_op_free(repl);
- if (ret != 0) {
- ERROR("could not free replenishment op\n");
- return NULL;
- }
-
- // check if there are pending replenishments
- if (list_empty(&server->replenishments.repl_list)) continue;
-
- list_for_each(pos, &server->replenishments.repl_list) {
- repl = list_entry(pos, frescan_repl_op_t, repl_list);
- break;
- }
-
- timerdata.it_value = repl->when;
+ "id:%u current_prio:%u\n", id, server->current_priority);
- DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
- "set timer to %d sec, %d nsec\n",
- repl->when.tv_sec, repl->when.tv_nsec);
+ server->current_priority = server->params.prio;
- ret = timer_settime(server->repl_timer,
- TIMER_ABSTIME, &timerdata, NULL);
- if (ret != 0) {
- ERROR("could not set replenishment timer\n");
- return NULL;
+ if (!list_empty(&server->packet_list.fifo_list)) {
+ clock_gettime (CLOCK_MONOTONIC, &server->act_time);
}
}
const struct timespec *timestamp)
{
int ret;
- frescan_repl_op_t *repl;
- bool empty;
+ frescan_repl_op_t *repl = NULL;
struct itimerspec timerdata;
frescan_server_data_t *server;
+ struct list_head *pos;
+ struct timespec now;
server = &the_servers_pool[net][ss];
- if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
- DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG, "ss in background\n");
- return 0;
- }
-
- repl = frescan_repl_op_alloc();
- if (repl == NULL) {
- ERROR("could not allocate a repl operation\n");
- return -1;
+ // extract the head
+ list_for_each(pos, &server->replenishments.repl_list) {
+ repl = list_entry(pos, frescan_repl_op_t, repl_list);
+ break;
}
+ list_del(&repl->repl_list);
+ // move to tail with new repl value
repl->when = *timestamp;
incr_timespec (&repl->when, &server->params.values.period);
repl->amount = 1;
- empty = list_empty(&server->replenishments.repl_list);
- DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG, "ss:%u, empty:%u\n", ss, empty);
-
list_add_tail(&repl->repl_list,
- &server->replenishments.repl_list);
+ &server->replenishments.repl_list);
+
+ // check the new head
+ list_for_each(pos, &server->replenishments.repl_list) {
+ repl = list_entry(pos, frescan_repl_op_t, repl_list);
+ break;
+ }
+
+ clock_gettime (CLOCK_MONOTONIC, &now);
+
+ if (smaller_timespec(&now, &repl->when)) {
+ server->current_priority = FRESCAN_BACKGROUND_PRIO;
- if (empty) {
timerdata.it_interval.tv_sec = 0;
timerdata.it_interval.tv_nsec = 0;
timerdata.it_value = repl->when;
--- /dev/null
+/*!
+ * @file frescan_servers_replenishments.c
+ *
+ * @brief the replenishment data and thread for the servers
+ *
+ * @version 0.01
+ *
+ * @date 12-Mar-2008
+ *
+ * @author
+ * Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This module contains the thread that waits for server's replenishment
+ * timer signals and perform the necessary replenishments.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include <time.h> // clock_gettime
+
+#include <misc/freelist.h> // freelist_t
+#include <misc/linux_list.h> // list_add_tail
+#include <misc/timespec_operations.h>
+
+#include "frescan_servers_replenishments.h"
+#include "frescan_config.h" // FRESCAN_MX_REPL_OPS
+#include "frescan_debug.h" // ERROR
+#include "frescan_data.h" // frescan_repl_op_t
+#include "fosa_threads_and_signals.h" // fosa_thread_attr_init...
+
+/**
+ * the_repl_op_pool - pool of replenishment operations
+ *
+ * We have a pool of replenishment operation structures and an associated
+ * freelist where we can get/put replenishment operations in O(1) time
+ *
+ * @the_repl_op_pool: array with the replenishment operations allocated
+ * @the_repl_op_pool_freelist: freelist for the_repl_op_pool
+ * @frescan_repl_op_init: initializes the freelist
+ * @frescan_repl_op_alloc: get a free replenishment operation structure
+ * @frescan_repl_op_free: free a replenishment operation structure
+ *
+ */
+
+static frescan_repl_op_t the_repl_op_pool[FRESCAN_MX_REPL_OPS];
+static freelist_t the_repl_op_pool_freelist;
+
+static int frescan_repl_op_init()
+{
+ return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
+}
+
+static frescan_repl_op_t *frescan_repl_op_alloc()
+{
+ int pos;
+
+ pos = freelist_alloc(&the_repl_op_pool_freelist);
+ if (pos == -1) {
+ ERROR("could not allocate repl op\n");
+ return NULL;
+ }
+ the_repl_op_pool[pos].pool_pos = pos; // to know how to free it
+ return &the_repl_op_pool[pos];
+}
+
+static int frescan_repl_op_free(frescan_repl_op_t *repl_op)
+{
+ return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
+}
+
+/**
+ * frescan_repl_thread - the thread that executes the replenishments
+ */
+
+static void *frescan_repl_thread(void *arg)
+{
+ int ret;
+ sigset_t set;
+ siginfo_t siginfo;
+ frescan_ss_t id;
+ frescan_network_t net;
+ struct list_head *pos;
+ frescan_repl_op_t *repl = NULL;
+ frescan_server_data_t *server;
+ struct itimerspec timerdata;
+
+ net = (frescan_network_t)(uint32_t)arg;
+ timerdata.it_interval.tv_sec = 0;
+ timerdata.it_interval.tv_nsec = 0;
+
+ sigemptyset(&set);
+ sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
+
+ while (1) {
+ ret = sigwaitinfo(&set, &siginfo);
+ if (ret == -1) {
+ ERROR("sigwaitinfo failed\n");
+ return NULL;
+ }
+
+ if (siginfo.si_signo != FRESCAN_REPL_SIGNAL_NUM) continue;
+
+ DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
+ "net:%u signal:%d code:%d value(server_id):%d\n",
+ net,
+ siginfo.si_signo, // FRESCAN_REPL_SIGNAL_NUM
+ siginfo.si_code, // SI_TIMER
+ siginfo.si_value.sival_int); // the server id
+
+ id = siginfo.si_value.sival_int;
+ server = &the_servers_pool[net][id];
+
+ DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
+ "id:%u, current_budget:%u, budget:%u, current_prio:%u\n",
+ id,
+ server->current_budget,
+ server->params.values.budget,
+ server->current_priority);
+
+ server->current_budget++;
+
+ if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
+ server->current_priority = server->params.prio;
+ if (!list_empty(&server->packet_list.fifo_list)) {
+ clock_gettime (CLOCK_MONOTONIC,
+ &server->act_time);
+ }
+ }
+
+ DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
+ "now... current_budget:%u, current_prio:%u\n",
+ server->current_budget,
+ server->current_priority);
+
+ // delete the replenishment of this call
+ list_for_each(pos, &server->replenishments.repl_list) {
+ repl = list_entry(pos, frescan_repl_op_t, repl_list);
+ break;
+ }
+
+ list_del(&repl->repl_list);
+
+ ret = frescan_repl_op_free(repl);
+ if (ret != 0) {
+ ERROR("could not free replenishment op\n");
+ return NULL;
+ }
+
+ // check if there are pending replenishments
+ if (list_empty(&server->replenishments.repl_list)) continue;
+
+ list_for_each(pos, &server->replenishments.repl_list) {
+ repl = list_entry(pos, frescan_repl_op_t, repl_list);
+ break;
+ }
+
+ timerdata.it_value = repl->when;
+
+ DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
+ "set timer to (%d, %d)\n",
+ repl->when.tv_sec, repl->when.tv_nsec);
+
+ ret = timer_settime(server->repl_timer,
+ TIMER_ABSTIME, &timerdata, NULL);
+ if (ret != 0) {
+ ERROR("could not set replenishment timer\n");
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * frescan_replenishments_init - init the replenishment structures and thread
+ *
+ * @net: the network instance
+ *
+ * Initialize the repl_op pool, set the mask for the timer signals and create
+ * the thread that will await for those signals and replenish the appropiate
+ * sporadic server.
+ */
+
+int frescan_replenishments_init(frescan_network_t net)
+{
+ int ret;
+ fosa_signal_t signal_set[1];
+ fosa_thread_attr_t attr;
+
+ ret = frescan_repl_op_init();
+ if (ret != 0) {
+ ERROR("could not init repl_op pool\n");
+ return ret;
+ }
+
+ signal_set[0] = FRESCAN_REPL_SIGNAL_NUM;
+
+ ret = fosa_set_accepted_signals(signal_set, 1);
+ if (ret != 0) {
+ ERROR("could not set the repl signal\n");
+ return ret;
+ }
+
+ // create the replenishment thread
+
+ ret = fosa_thread_attr_init(&attr);
+ if (ret != 0) {
+ ERROR("could not init thread attributes\n");
+ return ret;
+ }
+
+ ret = fosa_thread_attr_set_prio(&attr, FRESCAN_REPL_THREAD_PRIO);
+ if (ret != 0) {
+ ERROR("could not set repl thread prio %d\n",
+ FRESCAN_REPL_THREAD_PRIO);
+ return ret;
+ }
+
+ ret = fosa_thread_create(&the_networks[net].repl_thread_id,
+ &attr,
+ frescan_repl_thread,
+ (void *)(uint32_t)net);
+ if (ret != 0) {
+ ERROR("could not create the replenishment thread\n");
+ return ret;
+ }
+
+ ret = fosa_thread_attr_destroy(&attr);
+ if (ret != 0) {
+ ERROR("could not destroy thread attributes\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * frescan_replenishment_program - set a replenishment operation
+ *
+ * @net: the network instance
+ * @ss: the server
+ */
+
+int frescan_replenishment_program(frescan_network_t net,
+ frescan_ss_t ss,
+ const struct timespec *timestamp)
+{
+ int ret;
+ frescan_repl_op_t *repl;
+ bool empty;
+ struct itimerspec timerdata;
+ frescan_server_data_t *server;
+
+ server = &the_servers_pool[net][ss];
+
+ repl = frescan_repl_op_alloc();
+ if (repl == NULL) {
+ ERROR("could not allocate a repl operation\n");
+ return -1;
+ }
+
+ repl->when = *timestamp;
+ incr_timespec (&repl->when, &server->params.values.period);
+ repl->amount = 1;
+
+ empty = list_empty(&server->replenishments.repl_list);
+ DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG, "ss:%u, empty:%u\n", ss, empty);
+
+ list_add_tail(&repl->repl_list,
+ &server->replenishments.repl_list);
+
+ if (empty) {
+ timerdata.it_interval.tv_sec = 0;
+ timerdata.it_interval.tv_nsec = 0;
+ timerdata.it_value = repl->when;
+
+ DEBUG(FRESCAN_REPLENSH_ENABLE_DEBUG,
+ "set timer to %d sec, %d nsec\n",
+ repl->when.tv_sec, repl->when.tv_nsec);
+
+ ret = timer_settime(server->repl_timer,
+ TIMER_ABSTIME, &timerdata, NULL);
+ if (ret != 0) {
+ ERROR("could not set the replenishment timer\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
#include <time.h>
#include "frescan.h" // frescan_network_t
+#include "frescan_data.h"
/**
* frescan_replenishments_init - init the replenishment structures and thread
extern int frescan_replenishments_init(frescan_network_t net);
+extern frescan_repl_op_t *frescan_repl_op_alloc();
+
+extern int frescan_repl_op_free(frescan_repl_op_t *repl_op);
+
/**
* frescan_replenishment_program - set a replenishment operation
*