Subversion Repositories HelenOS

Rev

Rev 3990 | Rev 4192 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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 <rwlock.h>
  41. //#include <stdio.h>
  42. #include <string.h>
  43.  
  44. #include <sys/mman.h>
  45.  
  46. #include "../../err.h"
  47.  
  48. #include "../generic_field.h"
  49.  
  50. #include "packet_header.h"
  51. #include "packet.h"
  52.  
  53. /** Packet map page size.
  54.  */
  55. #define PACKET_MAP_SIZE 100
  56.  
  57. /** Returns the packet map page index.
  58.  *  @param packet_id The packet identifier.
  59.  */
  60. #define PACKET_MAP_PAGE( packet_id )    ((( packet_id ) - 1 ) / PACKET_MAP_SIZE )
  61.  
  62. /** Returns the packet index in the corresponding packet map page.
  63.  *  @param packet_id The packet identifier.
  64.  */
  65. #define PACKET_MAP_INDEX( packet_id )   ((( packet_id ) - 1 ) % PACKET_MAP_SIZE )
  66.  
  67. /** Type definition of the packet map page.
  68.  */
  69. typedef packet_t packet_map_t[ PACKET_MAP_SIZE ];
  70. /** Type definition of the packet map page pointer.
  71.  */
  72. typedef packet_map_t * packet_map_ref;
  73.  
  74. /** Packet map.
  75.  *  Maps packet identifiers to the packet references.
  76.  *  @see generic_field.h
  77.  */
  78. GENERIC_FIELD_DECLARE( gpm, packet_map_t );
  79.  
  80. /** Releases the packet.
  81.  *  @param packet The packet to be released. Input parameter.
  82.  *  @returns EOK on success.
  83.  *  @returns EINVAL if the packet is not valid.
  84.  */
  85. int packet_destroy( packet_t packet );
  86.  
  87. /** Packet map global data.
  88.  */
  89. static struct{
  90.     /** Safety lock.
  91.      */
  92.     rwlock_t    lock;
  93.     /** Packet map.
  94.      */
  95.     gpm_t   packet_map;
  96. } pm_globals;
  97.  
  98. GENERIC_FIELD_IMPLEMENT( gpm, packet_map_t );
  99.  
  100. int packet_destroy( packet_t packet ){
  101.     if( ! packet_is_valid( packet )) return EINVAL;
  102.     return munmap( packet, packet->length );
  103. }
  104.  
  105. int pm_init( void ){
  106.     ERROR_DECLARE;
  107.  
  108.     rwlock_initialize( & pm_globals.lock );
  109.     rwlock_write_lock( & pm_globals.lock );
  110.     ERROR_PROPAGATE( gpm_initialize( & pm_globals.packet_map ));
  111.     rwlock_write_unlock( & pm_globals.lock );
  112.     return EOK;
  113. }
  114.  
  115. packet_t pm_find( packet_id_t packet_id ){
  116.     packet_map_ref map;
  117.     packet_t packet;
  118.  
  119.     if( ! packet_id ) return NULL;
  120.     rwlock_read_lock( & pm_globals.lock );
  121.     if( packet_id > PACKET_MAP_SIZE * gpm_count( & pm_globals.packet_map )){
  122.         rwlock_read_unlock( & pm_globals.lock );
  123.         return NULL;
  124.     }
  125.     map = gpm_get_index( & pm_globals.packet_map, PACKET_MAP_PAGE( packet_id ));
  126.     if( ! map ){
  127.         rwlock_read_unlock( & pm_globals.lock );
  128.         return NULL;
  129.     }
  130.     packet = ( * map )[ PACKET_MAP_INDEX( packet_id ) ];
  131.     rwlock_read_unlock( & pm_globals.lock );
  132.     return packet;
  133. }
  134.  
  135. int pm_add( packet_t packet ){
  136.     ERROR_DECLARE;
  137.  
  138.     packet_map_ref map;
  139.  
  140.     if( ! packet_is_valid( packet )) return EINVAL;
  141.     rwlock_write_lock( & pm_globals.lock );
  142.     if( PACKET_MAP_PAGE( packet->packet_id ) < gpm_count( & pm_globals.packet_map )){
  143.         map = gpm_get_index( & pm_globals.packet_map, PACKET_MAP_PAGE( packet->packet_id ));
  144.     }else{
  145.         do{
  146.             map = ( packet_map_ref ) malloc( sizeof( packet_map_t ));
  147.             if( ! map ){
  148.                 rwlock_write_unlock( & pm_globals.lock );
  149.                 return ENOMEM;
  150.             }
  151.             memset( map, 0, sizeof( packet_map_t ));
  152.             if(( ERROR_CODE = gpm_add( & pm_globals.packet_map, map )) < 0 ){
  153.                 rwlock_write_unlock( & pm_globals.lock );
  154.                 free( map );
  155.                 return ERROR_CODE;
  156.             }
  157.         }while( PACKET_MAP_PAGE( packet->packet_id ) >= gpm_count( & pm_globals.packet_map ));
  158.     }
  159.     ( * map )[ PACKET_MAP_INDEX( packet->packet_id ) ] = packet;
  160.     rwlock_write_unlock( & pm_globals.lock );
  161.     return EOK;
  162. }
  163.  
  164. void pm_destroy( void ){
  165.     int count;
  166.     int index;
  167.     packet_map_ref map;
  168.     packet_t packet;
  169.  
  170.     rwlock_write_lock( & pm_globals.lock );
  171.     count = gpm_count( & pm_globals.packet_map );
  172.     while( count > 0 ){
  173.         map = gpm_get_index( & pm_globals.packet_map, count - 1 );
  174.         for( index = PACKET_MAP_SIZE - 1; index >= 0; -- index ){
  175.             packet = ( * map )[ index ];
  176.             if( packet_is_valid( packet )){
  177.                 munmap( packet, packet->length );
  178.             }
  179.         }
  180.     }
  181.     gpm_destroy( & pm_globals.packet_map );
  182.     // leave locked
  183. }
  184.  
  185. packet_t pq_add( packet_t first, packet_t packet, int order, size_t metric ){
  186.     packet_t    item;
  187.  
  188.     if( ! packet_is_valid( packet )) return NULL;
  189.     pq_set( packet, order, metric );
  190.     if( packet_is_valid( first )){
  191.         item = first;
  192.         do{
  193.             if( item->order < order ){
  194.                 if( item->next ){
  195.                     item = pm_find( item->next );
  196.                 }else{
  197.                     item->next = packet->packet_id;
  198.                     packet->previous = item->packet_id;
  199.                     return first;
  200.                 }
  201.             }else{
  202.                 packet->previous = item->previous;
  203.                 packet->next = item->packet_id;
  204.                 item->previous = packet->packet_id;
  205.                 item = pm_find( packet->previous );
  206.                 if( item ) item->next = packet->packet_id;
  207.                 return item;
  208.             }
  209.         }while( packet_is_valid( item ));
  210.     }
  211.     return packet;
  212. }
  213.  
  214. packet_t pq_detach( packet_t packet ){
  215.     packet_t next;
  216.     packet_t previous;
  217.  
  218.     if( ! packet_is_valid( packet )) return NULL;
  219.     next = pm_find( packet->next );
  220.     if( next ){
  221.         next->previous = packet->previous;
  222.         previous = pm_find( next->previous );
  223.         if( previous ){
  224.             previous->next = next->packet_id;
  225.         }
  226.     }
  227.     packet->previous = 0;
  228.     packet->next = 0;
  229.     return next;
  230. }
  231.  
  232. int pq_set( packet_t packet, int order, size_t metric ){
  233.     if( ! packet_is_valid( packet )) return EINVAL;
  234.     packet->order = order;
  235.     packet->metric = metric;
  236.     return EOK;
  237. }
  238.  
  239. void pq_destroy( packet_t first, void ( * packet_release )( packet_t packet )){
  240.     packet_t    actual;
  241.     packet_t    next;
  242.  
  243.     actual = first;
  244.     while( packet_is_valid( actual )){
  245.         next = pm_find( actual->next );
  246.         actual->next = 0;
  247.         actual->previous = 0;
  248.         if( packet_release ) packet_release( actual );
  249.         actual = next;
  250.     }
  251. }
  252.  
  253. packet_t pq_next( packet_t packet ){
  254.     if( ! packet_is_valid( packet )) return NULL;
  255.     return pm_find( packet->next );
  256. }
  257.  
  258. packet_t pq_previous( packet_t packet ){
  259.     if( ! packet_is_valid( packet )) return NULL;
  260.     return pm_find( packet->previous );
  261. }
  262.  
  263. /** @}
  264.  */
  265.