packet.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <malloc.h>
00039 #include <mem.h>
00040 #include <fibril_synch.h>
00041 #include <unistd.h>
00042 #include <errno.h>
00043 
00044 #include <sys/mman.h>
00045 
00046 #include <adt/generic_field.h>
00047 #include <net/packet.h>
00048 #include <net/packet_header.h>
00049 
00051 #define PACKET_MAP_SIZE 100
00052 
00056 #define PACKET_MAP_PAGE(packet_id)      (((packet_id) - 1) / PACKET_MAP_SIZE)
00057 
00061 #define PACKET_MAP_INDEX(packet_id)     (((packet_id) - 1) % PACKET_MAP_SIZE)
00062 
00064 typedef packet_t *packet_map_t[PACKET_MAP_SIZE];
00065 
00070 GENERIC_FIELD_DECLARE(gpm, packet_map_t);
00071 
00073 static struct {
00075         fibril_rwlock_t lock;
00077         gpm_t packet_map;
00078 } pm_globals;
00079 
00080 GENERIC_FIELD_IMPLEMENT(gpm, packet_map_t);
00081 
00087 int pm_init(void)
00088 {
00089         int rc;
00090 
00091         fibril_rwlock_initialize(&pm_globals.lock);
00092         
00093         fibril_rwlock_write_lock(&pm_globals.lock);
00094         rc = gpm_initialize(&pm_globals.packet_map);
00095         fibril_rwlock_write_unlock(&pm_globals.lock);
00096         
00097         return rc;
00098 }
00099 
00106 packet_t *pm_find(packet_id_t packet_id)
00107 {
00108         packet_map_t *map;
00109         packet_t *packet;
00110 
00111         if (!packet_id)
00112                 return NULL;
00113 
00114         fibril_rwlock_read_lock(&pm_globals.lock);
00115         if (packet_id > PACKET_MAP_SIZE * gpm_count(&pm_globals.packet_map)) {
00116                 fibril_rwlock_read_unlock(&pm_globals.lock);
00117                 return NULL;
00118         }
00119         map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet_id));
00120         if (!map) {
00121                 fibril_rwlock_read_unlock(&pm_globals.lock);
00122                 return NULL;
00123         }
00124         packet = (*map) [PACKET_MAP_INDEX(packet_id)];
00125         fibril_rwlock_read_unlock(&pm_globals.lock);
00126         return packet;
00127 }
00128 
00137 int pm_add(packet_t *packet)
00138 {
00139         packet_map_t *map;
00140         int rc;
00141 
00142         if (!packet_is_valid(packet))
00143                 return EINVAL;
00144 
00145         fibril_rwlock_write_lock(&pm_globals.lock);
00146 
00147         if (PACKET_MAP_PAGE(packet->packet_id) <
00148             gpm_count(&pm_globals.packet_map)) {
00149                 map = gpm_get_index(&pm_globals.packet_map,
00150                     PACKET_MAP_PAGE(packet->packet_id));
00151         } else {
00152                 do {
00153                         map = (packet_map_t *) malloc(sizeof(packet_map_t));
00154                         if (!map) {
00155                                 fibril_rwlock_write_unlock(&pm_globals.lock);
00156                                 return ENOMEM;
00157                         }
00158                         bzero(map, sizeof(packet_map_t));
00159                         rc = gpm_add(&pm_globals.packet_map, map);
00160                         if (rc < 0) {
00161                                 fibril_rwlock_write_unlock(&pm_globals.lock);
00162                                 free(map);
00163                                 return rc;
00164                         }
00165                 } while (PACKET_MAP_PAGE(packet->packet_id) >=
00166                     gpm_count(&pm_globals.packet_map));
00167         }
00168 
00169         (*map) [PACKET_MAP_INDEX(packet->packet_id)] = packet;
00170         fibril_rwlock_write_unlock(&pm_globals.lock);
00171         return EOK;
00172 }
00173 
00175 void pm_destroy(void)
00176 {
00177         int count;
00178         int index;
00179         packet_map_t *map;
00180         packet_t *packet;
00181 
00182         fibril_rwlock_write_lock(&pm_globals.lock);
00183         count = gpm_count(&pm_globals.packet_map);
00184         while (count > 0) {
00185                 map = gpm_get_index(&pm_globals.packet_map, count - 1);
00186                 for (index = PACKET_MAP_SIZE - 1; index >= 0; --index) {
00187                         packet = (*map)[index];
00188                         if (packet_is_valid(packet))
00189                                 munmap(packet, packet->length);
00190                 }
00191         }
00192         gpm_destroy(&pm_globals.packet_map, free);
00193         /* leave locked */
00194 }
00195 
00211 int pq_add(packet_t **first, packet_t *packet, size_t order, size_t metric)
00212 {
00213         packet_t *item;
00214 
00215         if (!first || !packet_is_valid(packet))
00216                 return EINVAL;
00217 
00218         pq_set_order(packet, order, metric);
00219         if (packet_is_valid(*first)) {
00220                 item = * first;
00221                 do {
00222                         if (item->order < order) {
00223                                 if (item->next) {
00224                                         item = pm_find(item->next);
00225                                 } else {
00226                                         item->next = packet->packet_id;
00227                                         packet->previous = item->packet_id;
00228                                         return EOK;
00229                                 }
00230                         } else {
00231                                 packet->previous = item->previous;
00232                                 packet->next = item->packet_id;
00233                                 item->previous = packet->packet_id;
00234                                 item = pm_find(packet->previous);
00235                                 if (item)
00236                                         item->next = packet->packet_id;
00237                                 else
00238                                         *first = packet;
00239                                 return EOK;
00240                         }
00241                 } while (packet_is_valid(item));
00242         }
00243         *first = packet;
00244         return EOK;
00245 }
00246 
00255 packet_t *pq_find(packet_t *packet, size_t order)
00256 {
00257         packet_t *item;
00258 
00259         if (!packet_is_valid(packet))
00260                 return NULL;
00261 
00262         item = packet;
00263         do {
00264                 if (item->order == order)
00265                         return item;
00266 
00267                 item = pm_find(item->next);
00268         } while (item && (item != packet) && packet_is_valid(item));
00269 
00270         return NULL;
00271 }
00272 
00280 int pq_insert_after(packet_t *packet, packet_t *new_packet)
00281 {
00282         packet_t *item;
00283 
00284         if (!packet_is_valid(packet) || !packet_is_valid(new_packet))
00285                 return EINVAL;
00286 
00287         new_packet->previous = packet->packet_id;
00288         new_packet->next = packet->next;
00289         item = pm_find(packet->next);
00290         if (item)
00291                 item->previous = new_packet->packet_id;
00292         packet->next = new_packet->packet_id;
00293 
00294         return EOK;
00295 }
00296 
00305 packet_t *pq_detach(packet_t *packet)
00306 {
00307         packet_t *next;
00308         packet_t *previous;
00309 
00310         if (!packet_is_valid(packet))
00311                 return NULL;
00312 
00313         next = pm_find(packet->next);
00314         if (next) {
00315                 next->previous = packet->previous;
00316                 previous = pm_find(next->previous);
00317                 if (previous)
00318                         previous->next = next->packet_id;
00319         }
00320         packet->previous = 0;
00321         packet->next = 0;
00322         return next;
00323 }
00324 
00333 int pq_set_order(packet_t *packet, size_t order, size_t metric)
00334 {
00335         if (!packet_is_valid(packet))
00336                 return EINVAL;
00337 
00338         packet->order = order;
00339         packet->metric = metric;
00340         return EOK;
00341 }
00342 
00351 int pq_get_order(packet_t *packet, size_t *order, size_t *metric)
00352 {
00353         if (!packet_is_valid(packet))
00354                 return EINVAL;
00355 
00356         if (order)
00357                 *order = packet->order;
00358 
00359         if (metric)
00360                 *metric = packet->metric;
00361 
00362         return EOK;
00363 }
00364 
00374 void pq_destroy(packet_t *first, void (*packet_release)(packet_t *packet))
00375 {
00376         packet_t *actual;
00377         packet_t *next;
00378 
00379         actual = first;
00380         while (packet_is_valid(actual)) {
00381                 next = pm_find(actual->next);
00382                 actual->next = 0;
00383                 actual->previous = 0;
00384                 if(packet_release)
00385                         packet_release(actual);
00386                 actual = next;
00387         }
00388 }
00389 
00397 packet_t *pq_next(packet_t *packet)
00398 {
00399         if (!packet_is_valid(packet))
00400                 return NULL;
00401 
00402         return pm_find(packet->next);
00403 }
00404 
00412 packet_t *pq_previous(packet_t *packet)
00413 {
00414         if (!packet_is_valid(packet))
00415                 return NULL;
00416 
00417         return pm_find(packet->previous);
00418 }
00419 

Generated on Thu Jun 2 07:45:46 2011 for HelenOS/USB by  doxygen 1.4.7