source: mainline/uspace/srv/net/structures/packet/packet.c@ b48ebd19

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b48ebd19 was 31c80a5, checked in by Lukas Mejdrech <lukasmejdrech@…>, 16 years ago
  • pq_find() fix
  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup packet
30 * @{
31 */
32
33/** @file
34 * Packet map and queue implementation.
35 * This file has to be compiled with both the packet server and the client.
36 */
37
38#include <errno.h>
39#include <malloc.h>
40#include <mem.h>
41#include <fibril_synch.h>
42//#include <stdio.h>
43#include <unistd.h>
44
45#include <sys/mman.h>
46
47#include "../../err.h"
48
49#include "../generic_field.h"
50
51#include "packet.h"
52#include "packet_header.h"
53
54/** Packet map page size.
55 */
56#define PACKET_MAP_SIZE 100
57
58/** Returns the packet map page index.
59 * @param[in] packet_id The packet identifier.
60 */
61#define PACKET_MAP_PAGE(packet_id) (((packet_id) - 1) / PACKET_MAP_SIZE)
62
63/** Returns the packet index in the corresponding packet map page.
64 * @param[in] packet_id The packet identifier.
65 */
66#define PACKET_MAP_INDEX(packet_id) (((packet_id) - 1) % PACKET_MAP_SIZE)
67
68/** Type definition of the packet map page.
69 */
70typedef packet_t packet_map_t[PACKET_MAP_SIZE];
71/** Type definition of the packet map page pointer.
72 */
73typedef packet_map_t * packet_map_ref;
74
75/** Packet map.
76 * Maps packet identifiers to the packet references.
77 * @see generic_field.h
78 */
79GENERIC_FIELD_DECLARE(gpm, packet_map_t);
80
81/** Releases the packet.
82 * @param[in] packet The packet to be released.
83 * @returns EOK on success.
84 * @returns EINVAL if the packet is not valid.
85 */
86int packet_destroy(packet_t packet);
87
88/** Packet map global data.
89 */
90static struct{
91 /** Safety lock.
92 */
93 fibril_rwlock_t lock;
94 /** Packet map.
95 */
96 gpm_t packet_map;
97} pm_globals;
98
99GENERIC_FIELD_IMPLEMENT(gpm, packet_map_t);
100
101int packet_destroy(packet_t packet){
102 if(! packet_is_valid(packet)){
103 return EINVAL;
104 }
105 return munmap(packet, packet->length);
106}
107
108int pm_init(void){
109 ERROR_DECLARE;
110
111 fibril_rwlock_initialize(&pm_globals.lock);
112 fibril_rwlock_write_lock(&pm_globals.lock);
113 ERROR_PROPAGATE(gpm_initialize(&pm_globals.packet_map));
114 fibril_rwlock_write_unlock(&pm_globals.lock);
115 return EOK;
116}
117
118packet_t pm_find(packet_id_t packet_id){
119 packet_map_ref map;
120 packet_t packet;
121
122 if(! packet_id){
123 return NULL;
124 }
125 fibril_rwlock_read_lock(&pm_globals.lock);
126 if(packet_id > PACKET_MAP_SIZE * gpm_count(&pm_globals.packet_map)){
127 fibril_rwlock_read_unlock(&pm_globals.lock);
128 return NULL;
129 }
130 map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet_id));
131 if(! map){
132 fibril_rwlock_read_unlock(&pm_globals.lock);
133 return NULL;
134 }
135 packet = (*map)[PACKET_MAP_INDEX(packet_id)];
136 fibril_rwlock_read_unlock(&pm_globals.lock);
137 return packet;
138}
139
140int pm_add(packet_t packet){
141 ERROR_DECLARE;
142
143 packet_map_ref map;
144
145 if(! packet_is_valid(packet)){
146 return EINVAL;
147 }
148 fibril_rwlock_write_lock(&pm_globals.lock);
149 if(PACKET_MAP_PAGE(packet->packet_id) < gpm_count(&pm_globals.packet_map)){
150 map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet->packet_id));
151 }else{
152 do{
153 map = (packet_map_ref) malloc(sizeof(packet_map_t));
154 if(! map){
155 fibril_rwlock_write_unlock(&pm_globals.lock);
156 return ENOMEM;
157 }
158 bzero(map, sizeof(packet_map_t));
159 if((ERROR_CODE = gpm_add(&pm_globals.packet_map, map)) < 0){
160 fibril_rwlock_write_unlock(&pm_globals.lock);
161 free(map);
162 return ERROR_CODE;
163 }
164 }while(PACKET_MAP_PAGE(packet->packet_id) >= gpm_count(&pm_globals.packet_map));
165 }
166 (*map)[PACKET_MAP_INDEX(packet->packet_id)] = packet;
167 fibril_rwlock_write_unlock(&pm_globals.lock);
168 return EOK;
169}
170
171void pm_destroy(void){
172 int count;
173 int index;
174 packet_map_ref map;
175 packet_t packet;
176
177 fibril_rwlock_write_lock(&pm_globals.lock);
178 count = gpm_count(&pm_globals.packet_map);
179 while(count > 0){
180 map = gpm_get_index(&pm_globals.packet_map, count - 1);
181 for(index = PACKET_MAP_SIZE - 1; index >= 0; -- index){
182 packet = (*map)[index];
183 if(packet_is_valid(packet)){
184 munmap(packet, packet->length);
185 }
186 }
187 }
188 gpm_destroy(&pm_globals.packet_map);
189 // leave locked
190}
191
192int pq_add(packet_t * first, packet_t packet, size_t order, size_t metric){
193 packet_t item;
194
195 if((! first) || (! packet_is_valid(packet))){
196 return EINVAL;
197 }
198 pq_set_order(packet, order, metric);
199 if(packet_is_valid(*first)){
200 item = * first;
201 do{
202 if(item->order < order){
203 if(item->next){
204 item = pm_find(item->next);
205 }else{
206 item->next = packet->packet_id;
207 packet->previous = item->packet_id;
208 return EOK;
209 }
210 }else{
211 packet->previous = item->previous;
212 packet->next = item->packet_id;
213 item->previous = packet->packet_id;
214 item = pm_find(packet->previous);
215 if(item){
216 item->next = packet->packet_id;
217 }else{
218 *first = packet;
219 }
220 return EOK;
221 }
222 }while(packet_is_valid(item));
223 }
224 *first = packet;
225 return EOK;
226}
227
228packet_t pq_find(packet_t packet, size_t order){
229 packet_t item;
230
231 if(! packet_is_valid(packet)){
232 return NULL;
233 }
234 item = packet;
235 do{
236 if(item->order == order){
237 return item;
238 }
239 item = pm_find(item->next);
240 }while(item && (item != packet) && packet_is_valid(item));
241 return NULL;
242}
243
244int pq_insert_after(packet_t packet, packet_t new_packet){
245 packet_t item;
246
247 if(!(packet_is_valid(packet) && packet_is_valid(new_packet))){
248 return EINVAL;
249 }
250 new_packet->previous = packet->packet_id;
251 new_packet->next = packet->next;
252 item = pm_find(packet->next);
253 if(item){
254 item->previous = new_packet->packet_id;
255 }
256 packet->next = new_packet->packet_id;
257 return EOK;
258}
259
260packet_t pq_detach(packet_t packet){
261 packet_t next;
262 packet_t previous;
263
264 if(! packet_is_valid(packet)){
265 return NULL;
266 }
267 next = pm_find(packet->next);
268 if(next){
269 next->previous = packet->previous;
270 previous = pm_find(next->previous);
271 if(previous){
272 previous->next = next->packet_id;
273 }
274 }
275 packet->previous = 0;
276 packet->next = 0;
277 return next;
278}
279
280int pq_set_order(packet_t packet, size_t order, size_t metric){
281 if(! packet_is_valid(packet)){
282 return EINVAL;
283 }
284 packet->order = order;
285 packet->metric = metric;
286 return EOK;
287}
288
289int pq_get_order(packet_t packet, size_t * order, size_t * metric){
290 if(! packet_is_valid(packet)){
291 return EINVAL;
292 }
293 if(order){
294 *order = packet->order;
295 }
296 if(metric){
297 *metric = packet->metric;
298 }
299 return EOK;
300}
301
302void pq_destroy(packet_t first, void (*packet_release)(packet_t packet)){
303 packet_t actual;
304 packet_t next;
305
306 actual = first;
307 while(packet_is_valid(actual)){
308 next = pm_find(actual->next);
309 actual->next = 0;
310 actual->previous = 0;
311 if(packet_release){
312 packet_release(actual);
313 }
314 actual = next;
315 }
316}
317
318packet_t pq_next(packet_t packet){
319 if(! packet_is_valid(packet)){
320 return NULL;
321 }
322 return pm_find(packet->next);
323}
324
325packet_t pq_previous(packet_t packet){
326 if(! packet_is_valid(packet)){
327 return NULL;
328 }
329 return pm_find(packet->previous);
330}
331
332/** @}
333 */
Note: See TracBrowser for help on using the repository browser.