Line data Source code
1 1 : /**
2 : * @file datatypes/msgchannel.c
3 : *
4 : * @brief A (M, 1) channel for messages.
5 : *
6 : * This module implements an (M, 1) channel to transfer message pointers.
7 : *
8 : * @copyright
9 : * Copyright (C) 2008-2019 HPDCS Group
10 : * https://hpdcs.github.io
11 : *
12 : * This file is part of ROOT-Sim (ROme OpTimistic Simulator).
13 : *
14 : * ROOT-Sim is free software; you can redistribute it and/or modify it under the
15 : * terms of the GNU General Public License as published by the Free Software
16 : * Foundation; only version 3 of the License applies.
17 : *
18 : * ROOT-Sim is distributed in the hope that it will be useful, but WITHOUT ANY
19 : * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
20 : * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 : *
22 : * You should have received a copy of the GNU General Public License along with
23 : * ROOT-Sim; if not, write to the Free Software Foundation, Inc.,
24 : * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 : *
26 : * @author Francesco Quaglia
27 : * @author Alessandro Pellegrini
28 : */
29 :
30 : #include <stdio.h>
31 : #include <stdlib.h>
32 : #include <string.h>
33 :
34 : #include <arch/atomic.h>
35 : #include <core/core.h>
36 : #include <communication/communication.h>
37 : #include <datatypes/list.h>
38 : #include <datatypes/msgchannel.h>
39 : #include <mm/mm.h>
40 :
41 : // These are used to simplify reading the code
42 0 : #define M_WRITE 0
43 0 : #define M_READ 1
44 :
45 0 : static void switch_channel_buffers(msg_channel * mc)
46 : {
47 : struct _msg_buff *volatile swap;
48 :
49 : mc->buffers[M_WRITE]->read = 0;
50 : mc->buffers[M_READ]->written = 0;
51 :
52 : swap = mc->buffers[M_WRITE];
53 : mc->buffers[M_WRITE] = mc->buffers[M_READ];
54 : mc->buffers[M_READ] = swap;
55 : }
56 :
57 0 : void fini_channel(msg_channel * mc)
58 : {
59 : rsfree((void *)mc->buffers[M_WRITE]->buffer);
60 : rsfree((void *)mc->buffers[M_READ]->buffer);
61 : rsfree(mc->buffers[M_WRITE]);
62 : rsfree(mc->buffers[M_READ]);
63 : rsfree(mc);
64 : }
65 :
66 0 : msg_channel *init_channel(void)
67 : {
68 : msg_channel *mc = rsalloc(sizeof(msg_channel));
69 :
70 : mc->buffers[M_READ] = rsalloc(sizeof(struct _msg_buff));
71 : mc->buffers[M_WRITE] = rsalloc(sizeof(struct _msg_buff));
72 :
73 : if (mc->buffers[M_READ] == NULL || mc->buffers[M_WRITE] == NULL)
74 : rootsim_error(true, "Unable to allocate message channel\n");
75 :
76 : mc->buffers[M_READ]->buffer =
77 : rsalloc(INITIAL_CHANNEL_SIZE * sizeof(msg_t *));
78 : mc->buffers[M_READ]->size = INITIAL_CHANNEL_SIZE;
79 : mc->buffers[M_READ]->written = 0;
80 : mc->buffers[M_READ]->read = 0;
81 :
82 : mc->buffers[M_WRITE]->buffer =
83 : rsalloc(INITIAL_CHANNEL_SIZE * sizeof(msg_t *));
84 : mc->buffers[M_WRITE]->size = INITIAL_CHANNEL_SIZE;
85 : mc->buffers[M_WRITE]->written = 0;
86 : mc->buffers[M_WRITE]->read = 0;
87 :
88 : if (mc->buffers[M_READ]->buffer == NULL
89 : || mc->buffers[M_WRITE]->buffer == NULL)
90 : rootsim_error(true, "Unable to allocate message channel\n");
91 :
92 : spinlock_init(&mc->write_lock);
93 :
94 : return mc;
95 : }
96 :
97 0 : void insert_msg(msg_channel * mc, msg_t * msg)
98 : {
99 :
100 : spin_lock(&mc->write_lock);
101 :
102 : // Reallocate the live BH buffer. Don't touch the other buffer,
103 : // as in this way the critical section is much shorter
104 : if (unlikely
105 : (mc->buffers[M_WRITE]->written == mc->buffers[M_WRITE]->size)) {
106 :
107 : mc->buffers[M_WRITE]->size *= 2;
108 : mc->buffers[M_WRITE]->buffer =
109 : rsrealloc((void *)mc->buffers[M_WRITE]->buffer,
110 : mc->buffers[M_WRITE]->size * sizeof(msg_t *));
111 :
112 : if (unlikely(mc->buffers[M_WRITE]->buffer == NULL))
113 : rootsim_error(true, "Unable to reallocate message channel\n");
114 :
115 : }
116 : #ifndef NDEBUG
117 : validate_msg(msg);
118 : #endif
119 :
120 : int index = mc->buffers[M_WRITE]->written++;
121 : mc->buffers[M_WRITE]->buffer[index] = msg;
122 :
123 : spin_unlock(&mc->write_lock);
124 : }
125 :
126 0 : void *get_msg(msg_channel * mc)
127 : {
128 : msg_t *msg = NULL;
129 :
130 : if (unlikely(mc->buffers[M_READ]->read == mc->buffers[M_READ]->written)) {
131 : spin_lock(&mc->write_lock);
132 : switch_channel_buffers(mc);
133 : spin_unlock(&mc->write_lock);
134 : }
135 :
136 : if (unlikely(mc->buffers[M_READ]->read == mc->buffers[M_READ]->written)) {
137 : goto leave;
138 : }
139 :
140 : int index = mc->buffers[M_READ]->read++;
141 : msg = mc->buffers[M_READ]->buffer[index];
142 : atomic_dec(&mc->size);
143 :
144 : #ifndef NDEBUG
145 : mc->buffers[M_READ]->buffer[index] = (void *)0xDEADB00B;
146 : validate_msg(msg);
147 : #endif
148 :
149 : leave:
150 : return msg;
151 : }
|