~jakub/helenos/ia64-revival

« back to all changes in this revision

Viewing changes to uspace/lib/c/generic/net/packet.c

  • Committer: Jakub Jermar
  • Date: 2011-04-13 14:45:41 UTC
  • mfrom: (527.1.397 main-clone)
  • Revision ID: jakub@jermar.eu-20110413144541-x0j3r1zxqhsljx1o
MergeĀ mainlineĀ changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
 */
28
28
 
29
 
/** @addtogroup packet
 
29
/** @addtogroup libc
30
30
 *  @{
31
31
 */
32
32
 
35
35
 *  This file has to be compiled with both the packet server and the client.
36
36
 */
37
37
 
38
 
#include <errno.h>
39
38
#include <malloc.h>
40
39
#include <mem.h>
41
40
#include <fibril_synch.h>
42
41
#include <unistd.h>
 
42
#include <errno.h>
43
43
 
44
44
#include <sys/mman.h>
45
45
 
46
 
#include <net_err.h>
47
46
#include <adt/generic_field.h>
48
 
#include <packet/packet.h>
49
 
#include <packet/packet_header.h>
 
47
#include <net/packet.h>
 
48
#include <net/packet_header.h>
50
49
 
51
 
/** Packet map page size.
52
 
 */
 
50
/** Packet map page size. */
53
51
#define PACKET_MAP_SIZE 100
54
52
 
55
53
/** Returns the packet map page index.
56
 
 *  @param[in] packet_id The packet identifier.
 
54
 * @param[in] packet_id The packet identifier.
57
55
 */
58
56
#define PACKET_MAP_PAGE(packet_id)      (((packet_id) - 1) / PACKET_MAP_SIZE)
59
57
 
62
60
 */
63
61
#define PACKET_MAP_INDEX(packet_id)     (((packet_id) - 1) % PACKET_MAP_SIZE)
64
62
 
65
 
/** Type definition of the packet map page.
66
 
 */
67
 
typedef packet_t packet_map_t[PACKET_MAP_SIZE];
68
 
/** Type definition of the packet map page pointer.
69
 
 */
70
 
typedef packet_map_t * packet_map_ref;
 
63
/** Type definition of the packet map page. */
 
64
typedef packet_t *packet_map_t[PACKET_MAP_SIZE];
71
65
 
72
66
/** Packet map.
73
 
 *  Maps packet identifiers to the packet references.
74
 
 *  @see generic_field.h
 
67
 * Maps packet identifiers to the packet references.
 
68
 * @see generic_field.h
75
69
 */
76
70
GENERIC_FIELD_DECLARE(gpm, packet_map_t);
77
71
 
78
 
/** Releases the packet.
79
 
 *  @param[in] packet The packet to be released.
80
 
 *  @returns EOK on success.
81
 
 *  @returns EINVAL if the packet is not valid.
82
 
 */
83
 
int packet_destroy(packet_t packet);
84
 
 
85
 
/** Packet map global data.
86
 
 */
87
 
static struct{
88
 
        /** Safety lock.
89
 
         */
 
72
/** Packet map global data. */
 
73
static struct {
 
74
        /** Safety lock. */
90
75
        fibril_rwlock_t lock;
91
 
        /** Packet map.
92
 
         */
 
76
        /** Packet map. */
93
77
        gpm_t packet_map;
94
78
} pm_globals;
95
79
 
96
80
GENERIC_FIELD_IMPLEMENT(gpm, packet_map_t);
97
81
 
98
 
int packet_destroy(packet_t packet){
99
 
        if(! packet_is_valid(packet)){
100
 
                return EINVAL;
101
 
        }
102
 
        return munmap(packet, packet->length);
103
 
}
104
 
 
105
 
int pm_init(void){
106
 
        ERROR_DECLARE;
 
82
/** Initializes the packet map.
 
83
 *
 
84
 * @return              EOK on success.
 
85
 * @return              ENOMEM if there is not enough memory left.
 
86
 */
 
87
int pm_init(void)
 
88
{
 
89
        int rc;
107
90
 
108
91
        fibril_rwlock_initialize(&pm_globals.lock);
 
92
        
109
93
        fibril_rwlock_write_lock(&pm_globals.lock);
110
 
        ERROR_PROPAGATE(gpm_initialize(&pm_globals.packet_map));
 
94
        rc = gpm_initialize(&pm_globals.packet_map);
111
95
        fibril_rwlock_write_unlock(&pm_globals.lock);
112
 
        return EOK;
 
96
        
 
97
        return rc;
113
98
}
114
99
 
115
 
packet_t pm_find(packet_id_t packet_id){
116
 
        packet_map_ref map;
117
 
        packet_t packet;
 
100
/** Finds the packet mapping.
 
101
 *
 
102
 * @param[in] packet_id The packet identifier to be found.
 
103
 * @return              The found packet reference.
 
104
 * @return              NULL if the mapping does not exist.
 
105
 */
 
106
packet_t *pm_find(packet_id_t packet_id)
 
107
{
 
108
        packet_map_t *map;
 
109
        packet_t *packet;
118
110
 
119
 
        if(! packet_id){
 
111
        if (!packet_id)
120
112
                return NULL;
121
 
        }
 
113
 
122
114
        fibril_rwlock_read_lock(&pm_globals.lock);
123
 
        if(packet_id > PACKET_MAP_SIZE * gpm_count(&pm_globals.packet_map)){
 
115
        if (packet_id > PACKET_MAP_SIZE * gpm_count(&pm_globals.packet_map)) {
124
116
                fibril_rwlock_read_unlock(&pm_globals.lock);
125
117
                return NULL;
126
118
        }
127
119
        map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet_id));
128
 
        if(! map){
 
120
        if (!map) {
129
121
                fibril_rwlock_read_unlock(&pm_globals.lock);
130
122
                return NULL;
131
123
        }
132
 
        packet = (*map)[PACKET_MAP_INDEX(packet_id)];
 
124
        packet = (*map) [PACKET_MAP_INDEX(packet_id)];
133
125
        fibril_rwlock_read_unlock(&pm_globals.lock);
134
126
        return packet;
135
127
}
136
128
 
137
 
int pm_add(packet_t packet){
138
 
        ERROR_DECLARE;
139
 
 
140
 
        packet_map_ref map;
141
 
 
142
 
        if(! packet_is_valid(packet)){
 
129
/** Adds the packet mapping.
 
130
 *
 
131
 * @param[in] packet    The packet to be remembered.
 
132
 * @return              EOK on success.
 
133
 * @return              EINVAL if the packet is not valid.
 
134
 * @return              EINVAL if the packet map is not initialized.
 
135
 * @return              ENOMEM if there is not enough memory left.
 
136
 */
 
137
int pm_add(packet_t *packet)
 
138
{
 
139
        packet_map_t *map;
 
140
        int rc;
 
141
 
 
142
        if (!packet_is_valid(packet))
143
143
                return EINVAL;
144
 
        }
 
144
 
145
145
        fibril_rwlock_write_lock(&pm_globals.lock);
146
 
        if(PACKET_MAP_PAGE(packet->packet_id) < gpm_count(&pm_globals.packet_map)){
147
 
                map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet->packet_id));
148
 
        }else{
149
 
                do{
150
 
                        map = (packet_map_ref) malloc(sizeof(packet_map_t));
151
 
                        if(! map){
 
146
 
 
147
        if (PACKET_MAP_PAGE(packet->packet_id) <
 
148
            gpm_count(&pm_globals.packet_map)) {
 
149
                map = gpm_get_index(&pm_globals.packet_map,
 
150
                    PACKET_MAP_PAGE(packet->packet_id));
 
151
        } else {
 
152
                do {
 
153
                        map = (packet_map_t *) malloc(sizeof(packet_map_t));
 
154
                        if (!map) {
152
155
                                fibril_rwlock_write_unlock(&pm_globals.lock);
153
156
                                return ENOMEM;
154
157
                        }
155
158
                        bzero(map, sizeof(packet_map_t));
156
 
                        if((ERROR_CODE = gpm_add(&pm_globals.packet_map, map)) < 0){
 
159
                        rc = gpm_add(&pm_globals.packet_map, map);
 
160
                        if (rc < 0) {
157
161
                                fibril_rwlock_write_unlock(&pm_globals.lock);
158
162
                                free(map);
159
 
                                return ERROR_CODE;
 
163
                                return rc;
160
164
                        }
161
 
                }while(PACKET_MAP_PAGE(packet->packet_id) >= gpm_count(&pm_globals.packet_map));
 
165
                } while (PACKET_MAP_PAGE(packet->packet_id) >=
 
166
                    gpm_count(&pm_globals.packet_map));
162
167
        }
163
 
        (*map)[PACKET_MAP_INDEX(packet->packet_id)] = packet;
 
168
 
 
169
        (*map) [PACKET_MAP_INDEX(packet->packet_id)] = packet;
164
170
        fibril_rwlock_write_unlock(&pm_globals.lock);
165
171
        return EOK;
166
172
}
167
173
 
168
 
void pm_destroy(void){
 
174
/** Releases the packet map. */
 
175
void pm_destroy(void)
 
176
{
169
177
        int count;
170
178
        int index;
171
 
        packet_map_ref map;
172
 
        packet_t packet;
 
179
        packet_map_t *map;
 
180
        packet_t *packet;
173
181
 
174
182
        fibril_rwlock_write_lock(&pm_globals.lock);
175
183
        count = gpm_count(&pm_globals.packet_map);
176
 
        while(count > 0){
 
184
        while (count > 0) {
177
185
                map = gpm_get_index(&pm_globals.packet_map, count - 1);
178
 
                for(index = PACKET_MAP_SIZE - 1; index >= 0; -- index){
 
186
                for (index = PACKET_MAP_SIZE - 1; index >= 0; --index) {
179
187
                        packet = (*map)[index];
180
 
                        if(packet_is_valid(packet)){
 
188
                        if (packet_is_valid(packet))
181
189
                                munmap(packet, packet->length);
182
 
                        }
183
190
                }
184
191
        }
185
 
        gpm_destroy(&pm_globals.packet_map);
186
 
        // leave locked
 
192
        gpm_destroy(&pm_globals.packet_map, free);
 
193
        /* leave locked */
187
194
}
188
195
 
189
 
int pq_add(packet_t * first, packet_t packet, size_t order, size_t metric){
190
 
        packet_t item;
 
196
/** Add packet to the sorted queue.
 
197
 *
 
198
 * The queue is sorted in the ascending order.
 
199
 * The packet is inserted right before the packets of the same order value.
 
200
 *
 
201
 * @param[in,out] first The first packet of the queue. Sets the first packet of
 
202
 *                      the queue. The original first packet may be shifted by
 
203
 *                      the new packet.
 
204
 * @param[in] packet    The packet to be added.
 
205
 * @param[in] order     The packet order value.
 
206
 * @param[in] metric    The metric value of the packet.
 
207
 * @return              EOK on success.
 
208
 * @return              EINVAL if the first parameter is NULL.
 
209
 * @return              EINVAL if the packet is not valid.
 
210
 */
 
211
int pq_add(packet_t **first, packet_t *packet, size_t order, size_t metric)
 
212
{
 
213
        packet_t *item;
191
214
 
192
 
        if((! first) || (! packet_is_valid(packet))){
 
215
        if (!first || !packet_is_valid(packet))
193
216
                return EINVAL;
194
 
        }
 
217
 
195
218
        pq_set_order(packet, order, metric);
196
 
        if(packet_is_valid(*first)){
 
219
        if (packet_is_valid(*first)) {
197
220
                item = * first;
198
 
                do{
199
 
                        if(item->order < order){
200
 
                                if(item->next){
 
221
                do {
 
222
                        if (item->order < order) {
 
223
                                if (item->next) {
201
224
                                        item = pm_find(item->next);
202
 
                                }else{
 
225
                                } else {
203
226
                                        item->next = packet->packet_id;
204
227
                                        packet->previous = item->packet_id;
205
228
                                        return EOK;
206
229
                                }
207
 
                        }else{
 
230
                        } else {
208
231
                                packet->previous = item->previous;
209
232
                                packet->next = item->packet_id;
210
233
                                item->previous = packet->packet_id;
211
234
                                item = pm_find(packet->previous);
212
 
                                if(item){
 
235
                                if (item)
213
236
                                        item->next = packet->packet_id;
214
 
                                }else{
 
237
                                else
215
238
                                        *first = packet;
216
 
                                }
217
239
                                return EOK;
218
240
                        }
219
 
                }while(packet_is_valid(item));
 
241
                } while (packet_is_valid(item));
220
242
        }
221
243
        *first = packet;
222
244
        return EOK;
223
245
}
224
246
 
225
 
packet_t pq_find(packet_t packet, size_t order){
226
 
        packet_t item;
 
247
/** Finds the packet with the given order.
 
248
 *
 
249
 * @param[in] first     The first packet of the queue.
 
250
 * @param[in] order     The packet order value.
 
251
 * @return              The packet with the given order.
 
252
 * @return              NULL if the first packet is not valid.
 
253
 * @return              NULL if the packet is not found.
 
254
 */
 
255
packet_t *pq_find(packet_t *packet, size_t order)
 
256
{
 
257
        packet_t *item;
227
258
 
228
 
        if(! packet_is_valid(packet)){
 
259
        if (!packet_is_valid(packet))
229
260
                return NULL;
230
 
        }
 
261
 
231
262
        item = packet;
232
 
        do{
233
 
                if(item->order == order){
 
263
        do {
 
264
                if (item->order == order)
234
265
                        return item;
235
 
                }
 
266
 
236
267
                item = pm_find(item->next);
237
 
        }while(item && (item != packet) && packet_is_valid(item));
 
268
        } while (item && (item != packet) && packet_is_valid(item));
 
269
 
238
270
        return NULL;
239
271
}
240
272
 
241
 
int pq_insert_after(packet_t packet, packet_t new_packet){
242
 
        packet_t item;
 
273
/** Inserts packet after the given one.
 
274
 *
 
275
 * @param[in] packet    The packet in the queue.
 
276
 * @param[in] new_packet The new packet to be inserted.
 
277
 * @return              EOK on success.
 
278
 * @return              EINVAL if etiher of the packets is invalid.
 
279
 */
 
280
int pq_insert_after(packet_t *packet, packet_t *new_packet)
 
281
{
 
282
        packet_t *item;
243
283
 
244
 
        if(!(packet_is_valid(packet) && packet_is_valid(new_packet))){
 
284
        if (!packet_is_valid(packet) || !packet_is_valid(new_packet))
245
285
                return EINVAL;
246
 
        }
 
286
 
247
287
        new_packet->previous = packet->packet_id;
248
288
        new_packet->next = packet->next;
249
289
        item = pm_find(packet->next);
250
 
        if(item){
 
290
        if (item)
251
291
                item->previous = new_packet->packet_id;
252
 
        }
253
292
        packet->next = new_packet->packet_id;
 
293
 
254
294
        return EOK;
255
295
}
256
296
 
257
 
packet_t pq_detach(packet_t packet){
258
 
        packet_t next;
259
 
        packet_t previous;
 
297
/** Detach the packet from the queue.
 
298
 *
 
299
 * @param[in] packet    The packet to be detached.
 
300
 * @return              The next packet in the queue. If the packet is the first
 
301
 *                      one of the queue, this becomes the new first one.
 
302
 * @return              NULL if there is no packet left.
 
303
 * @return              NULL if the packet is not valid.
 
304
 */
 
305
packet_t *pq_detach(packet_t *packet)
 
306
{
 
307
        packet_t *next;
 
308
        packet_t *previous;
260
309
 
261
 
        if(! packet_is_valid(packet)){
 
310
        if (!packet_is_valid(packet))
262
311
                return NULL;
263
 
        }
 
312
 
264
313
        next = pm_find(packet->next);
265
 
        if(next){
 
314
        if (next) {
266
315
                next->previous = packet->previous;
267
316
                previous = pm_find(next->previous);
268
 
                if(previous){
 
317
                if (previous)
269
318
                        previous->next = next->packet_id;
270
 
                }
271
319
        }
272
320
        packet->previous = 0;
273
321
        packet->next = 0;
274
322
        return next;
275
323
}
276
324
 
277
 
int pq_set_order(packet_t packet, size_t order, size_t metric){
278
 
        if(! packet_is_valid(packet)){
 
325
/** Sets the packet order and metric attributes.
 
326
 *
 
327
 * @param[in] packeti   The packet to be set.
 
328
 * @param[in] order     The packet order value.
 
329
 * @param[in] metric    The metric value of the packet.
 
330
 * @return              EOK on success.
 
331
 * @return              EINVAL if the packet is invalid.
 
332
 */
 
333
int pq_set_order(packet_t *packet, size_t order, size_t metric)
 
334
{
 
335
        if (!packet_is_valid(packet))
279
336
                return EINVAL;
280
 
        }
 
337
 
281
338
        packet->order = order;
282
339
        packet->metric = metric;
283
340
        return EOK;
284
341
}
285
342
 
286
 
int pq_get_order(packet_t packet, size_t * order, size_t * metric){
287
 
        if(! packet_is_valid(packet)){
 
343
/** Sets the packet order and metric attributes.
 
344
 *
 
345
 * @param[in] packet    The packet to be set.
 
346
 * @param[out] order    The packet order value.
 
347
 * @param[out] metric   The metric value of the packet.
 
348
 * @return              EOK on success.
 
349
 * @return              EINVAL if the packet is invalid.
 
350
 */
 
351
int pq_get_order(packet_t *packet, size_t *order, size_t *metric)
 
352
{
 
353
        if (!packet_is_valid(packet))
288
354
                return EINVAL;
289
 
        }
290
 
        if(order){
 
355
 
 
356
        if (order)
291
357
                *order = packet->order;
292
 
        }
293
 
        if(metric){
 
358
 
 
359
        if (metric)
294
360
                *metric = packet->metric;
295
 
        }
 
361
 
296
362
        return EOK;
297
363
}
298
364
 
299
 
void pq_destroy(packet_t first, void (*packet_release)(packet_t packet)){
300
 
        packet_t actual;
301
 
        packet_t next;
 
365
/** Releases the whole queue.
 
366
 *
 
367
 * Detaches all packets of the queue and calls the packet_release() for each of
 
368
 * them.
 
369
 *
 
370
 * @param[in] first     The first packet of the queue.
 
371
 * @param[in] packet_release The releasing function called for each of the
 
372
 *                      packets after its detachment.
 
373
 */
 
374
void pq_destroy(packet_t *first, void (*packet_release)(packet_t *packet))
 
375
{
 
376
        packet_t *actual;
 
377
        packet_t *next;
302
378
 
303
379
        actual = first;
304
 
        while(packet_is_valid(actual)){
 
380
        while (packet_is_valid(actual)) {
305
381
                next = pm_find(actual->next);
306
382
                actual->next = 0;
307
383
                actual->previous = 0;
308
 
                if(packet_release){
 
384
                if(packet_release)
309
385
                        packet_release(actual);
310
 
                }
311
386
                actual = next;
312
387
        }
313
388
}
314
389
 
315
 
packet_t pq_next(packet_t packet){
316
 
        if(! packet_is_valid(packet)){
 
390
/** Returns the next packet in the queue.
 
391
 *
 
392
 * @param[in] packet    The packet queue member.
 
393
 * @return              The next packet in the queue.
 
394
 * @return              NULL if there is no next packet.
 
395
 * @return              NULL if the packet is not valid.
 
396
 */
 
397
packet_t *pq_next(packet_t *packet)
 
398
{
 
399
        if (!packet_is_valid(packet))
317
400
                return NULL;
318
 
        }
 
401
 
319
402
        return pm_find(packet->next);
320
403
}
321
404
 
322
 
packet_t pq_previous(packet_t packet){
323
 
        if(! packet_is_valid(packet)){
 
405
/** Returns the previous packet in the queue.
 
406
 *
 
407
 * @param[in] packet    The packet queue member.
 
408
 * @return              The previous packet in the queue.
 
409
 * @return              NULL if there is no previous packet.
 
410
 * @return              NULL if the packet is not valid.
 
411
 */
 
412
packet_t *pq_previous(packet_t *packet)
 
413
{
 
414
        if (!packet_is_valid(packet))
324
415
                return NULL;
325
 
        }
 
416
 
326
417
        return pm_find(packet->previous);
327
418
}
328
419