Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

irqueue.c

Go to the documentation of this file.
00001 /*********************************************************************
00002  *                
00003  * Filename:      irqueue.c
00004  * Version:       0.3
00005  * Description:   General queue implementation
00006  * Status:        Experimental.
00007  * Author:        Dag Brattli <dagb@cs.uit.no>
00008  * Created at:    Tue Jun  9 13:29:31 1998
00009  * Modified at:   Sun Dec 12 13:48:22 1999
00010  * Modified by:   Dag Brattli <dagb@cs.uit.no>
00011  * 
00012  *     Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no>
00013  *     Copyright (C) 1998, Dag Brattli, 
00014  *     All Rights Reserved.
00015  *
00016  *     This code is taken from the Vortex Operating System written by Aage
00017  *     Kvalnes. Aage has agreed that this code can use the GPL licence,
00018  *     although he does not use that licence in his own code.
00019  *     
00020  *     This copyright does however _not_ include the ELF hash() function
00021  *     which I currently don't know which licence or copyright it
00022  *     has. Please inform me if you know.
00023  *      
00024  *     This program is free software; you can redistribute it and/or 
00025  *     modify it under the terms of the GNU General Public License as 
00026  *     published by the Free Software Foundation; either version 2 of 
00027  *     the License, or (at your option) any later version.
00028  *  
00029  *     Neither Dag Brattli nor University of Tromsų admit liability nor
00030  *     provide warranty for any of this software. This material is 
00031  *     provided "AS-IS" and at no charge.
00032  *     
00033  ********************************************************************/
00034 
00035 #include <net/irda/irda.h>
00036 #include <net/irda/irqueue.h>
00037 #include <net/irda/irmod.h>
00038 
00039 static queue_t *dequeue_general( queue_t **queue, queue_t* element);
00040 static __u32 hash( char* name);
00041 
00042 /*
00043  * Function hashbin_create ( type, name )
00044  *
00045  *    Create hashbin!
00046  *
00047  */
00048 hashbin_t *hashbin_new(int type)
00049 {
00050         hashbin_t* hashbin;
00051         int i;
00052         
00053         /*
00054          * Allocate new hashbin
00055          */
00056         hashbin = kmalloc( sizeof(hashbin_t), GFP_ATOMIC);
00057         if (!hashbin)
00058                 return NULL;
00059 
00060         /*
00061          * Initialize structure
00062          */
00063         memset(hashbin, 0, sizeof(hashbin_t));
00064         hashbin->hb_type = type;
00065         hashbin->magic = HB_MAGIC;
00066 
00067         /* Make sure all spinlock's are unlocked */
00068         for (i=0;i<HASHBIN_SIZE;i++)
00069                 hashbin->hb_mutex[i] = SPIN_LOCK_UNLOCKED;
00070         
00071         return hashbin;
00072 }
00073 
00074 /*
00075  * Function hashbin_clear (hashbin, free_func)
00076  *
00077  *    Remove all entries from the hashbin, see also the comments in 
00078  *    hashbin_delete() below
00079  */
00080 int hashbin_clear( hashbin_t* hashbin, FREE_FUNC free_func)
00081 {
00082         queue_t* queue;
00083         int i;
00084         
00085         ASSERT(hashbin != NULL, return -1;);
00086         ASSERT(hashbin->magic == HB_MAGIC, return -1;);
00087 
00088         /*
00089          * Free the entries in the hashbin
00090          */
00091         for (i = 0; i < HASHBIN_SIZE; i ++ ) {
00092                 queue = dequeue_first( (queue_t**) &hashbin->hb_queue[i]);
00093                 while (queue) {
00094                         if (free_func)
00095                                 (*free_func)(queue);
00096                         queue = dequeue_first( 
00097                                 (queue_t**) &hashbin->hb_queue[i]);
00098                 }
00099         }
00100         hashbin->hb_size = 0;
00101 
00102         return 0;
00103 }
00104 
00105 
00106 /*
00107  * Function hashbin_delete (hashbin, free_func)
00108  *
00109  *    Destroy hashbin, the free_func can be a user supplied special routine 
00110  *    for deallocating this structure if it's complex. If not the user can 
00111  *    just supply kfree, which should take care of the job.
00112  */
00113 int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
00114 {
00115         queue_t* queue;
00116         int i;
00117 
00118         ASSERT(hashbin != NULL, return -1;);
00119         ASSERT(hashbin->magic == HB_MAGIC, return -1;);
00120         
00121         /*
00122          *  Free the entries in the hashbin, TODO: use hashbin_clear when
00123          *  it has been shown to work
00124          */
00125         for (i = 0; i < HASHBIN_SIZE; i ++ ) {
00126                 queue = dequeue_first((queue_t**) &hashbin->hb_queue[i]);
00127                 while (queue ) {
00128                         if (free_func)
00129                                 (*free_func)(queue);
00130                         queue = dequeue_first( 
00131                                 (queue_t**) &hashbin->hb_queue[i]);
00132                 }
00133         }
00134         
00135         /*
00136          *  Free the hashbin structure
00137          */
00138         hashbin->magic = ~HB_MAGIC;
00139         kfree(hashbin);
00140 
00141         return 0;
00142 }
00143 
00144 /*
00145  * Function hashbin_lock (hashbin, hashv, name)
00146  *
00147  *    Lock the hashbin
00148  *
00149  */
00150 void hashbin_lock(hashbin_t* hashbin, __u32 hashv, char* name, 
00151                   unsigned long flags)
00152 {
00153         int bin;
00154         
00155         IRDA_DEBUG(0, "hashbin_lock\n");
00156 
00157         ASSERT(hashbin != NULL, return;);
00158         ASSERT(hashbin->magic == HB_MAGIC, return;);
00159 
00160         /*
00161          * Locate hashbin
00162          */
00163         if (name)
00164                 hashv = hash(name);
00165         bin = GET_HASHBIN(hashv);
00166         
00167         /* Synchronize */
00168         if ( hashbin->hb_type & HB_GLOBAL )
00169                 spin_lock_irqsave(&hashbin->hb_mutex[ bin], flags);
00170         else {
00171                 save_flags(flags);
00172                 cli();
00173         }
00174 }
00175 
00176 /*
00177  * Function hashbin_unlock (hashbin, hashv, name)
00178  *
00179  *    Unlock the hashbin
00180  *
00181  */
00182 void hashbin_unlock(hashbin_t* hashbin, __u32 hashv, char* name, 
00183                     unsigned long flags)
00184 {
00185         int bin;
00186 
00187         IRDA_DEBUG(0, "hashbin_unlock()\n");
00188 
00189         ASSERT(hashbin != NULL, return;);
00190         ASSERT(hashbin->magic == HB_MAGIC, return;);
00191         
00192         /*
00193          * Locate hashbin
00194          */
00195         if (name )
00196                 hashv = hash(name);
00197         bin = GET_HASHBIN(hashv);
00198         
00199         /* Release lock */
00200         if ( hashbin->hb_type & HB_GLOBAL)
00201                 spin_unlock_irq( &hashbin->hb_mutex[ bin]);
00202         else if (hashbin->hb_type & HB_LOCAL) {
00203                 restore_flags( flags);
00204         }
00205 }
00206 
00207 /*
00208  * Function hashbin_insert (hashbin, entry, name)
00209  *
00210  *    Insert an entry into the hashbin
00211  *
00212  */
00213 void hashbin_insert(hashbin_t* hashbin, queue_t* entry, __u32 hashv, char* name)
00214 {
00215         unsigned long flags = 0;
00216         int bin;
00217 
00218         IRDA_DEBUG( 4, __FUNCTION__"()\n");
00219 
00220         ASSERT( hashbin != NULL, return;);
00221         ASSERT( hashbin->magic == HB_MAGIC, return;);
00222 
00223         /*
00224          * Locate hashbin
00225          */
00226         if ( name )
00227                 hashv = hash( name );
00228         bin = GET_HASHBIN( hashv );
00229 
00230         /* Synchronize */
00231         if ( hashbin->hb_type & HB_GLOBAL ) {
00232                 spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
00233 
00234         } else if ( hashbin->hb_type & HB_LOCAL ) {
00235                 save_flags(flags);
00236                 cli();
00237         } /* Default is no-lock  */
00238         
00239         /*
00240          * Store name and key
00241          */
00242         entry->q_hash = hashv;
00243         if ( name )
00244                 strncpy( entry->q_name, name, 32);
00245         
00246         /*
00247          * Insert new entry first
00248          * TODO: Perhaps allow sorted lists?
00249          *       -> Merge sort if a sorted list should be created
00250          */
00251         if ( hashbin->hb_type & HB_SORTED) {
00252         } else {
00253                 enqueue_first( (queue_t**) &hashbin->hb_queue[ bin ],
00254                                entry);
00255         }
00256         hashbin->hb_size++;
00257 
00258         /* Release lock */
00259         if ( hashbin->hb_type & HB_GLOBAL) {
00260 
00261                 spin_unlock_irq( &hashbin->hb_mutex[ bin]);
00262 
00263         } else if ( hashbin->hb_type & HB_LOCAL) {
00264                 restore_flags( flags);
00265         }
00266 }
00267 
00268 /*
00269  * Function hashbin_find (hashbin, hashv, name)
00270  *
00271  *    Find item with the given hashv or name
00272  *
00273  */
00274 void* hashbin_find( hashbin_t* hashbin, __u32 hashv, char* name )
00275 {
00276         int bin, found = FALSE;
00277         unsigned long flags = 0;
00278         queue_t* entry;
00279 
00280         IRDA_DEBUG( 4, "hashbin_find()\n");
00281 
00282         ASSERT( hashbin != NULL, return NULL;);
00283         ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
00284 
00285         /*
00286          * Locate hashbin
00287          */
00288         if ( name )
00289                 hashv = hash( name );
00290         bin = GET_HASHBIN( hashv );
00291         
00292         /* Synchronize */
00293         if ( hashbin->hb_type & HB_GLOBAL ) {
00294                 spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
00295 
00296         } else if ( hashbin->hb_type & HB_LOCAL ) {
00297                 save_flags(flags);
00298                 cli();
00299         } /* Default is no-lock  */
00300         
00301         /*
00302          * Search for entry
00303          */
00304         entry = hashbin->hb_queue[ bin];
00305         if ( entry ) {
00306                 do {
00307                         /*
00308                          * Check for key
00309                          */
00310                         if ( entry->q_hash == hashv ) {
00311                                 /*
00312                                  * Name compare too?
00313                                  */
00314                                 if ( name ) {
00315                                         if ( strcmp( entry->q_name, name ) == 0 ) {
00316                                                 found = TRUE;
00317                                                 break;
00318                                         }
00319                                 } else {
00320                                         found = TRUE;
00321                                         break;
00322                                 }
00323                         }
00324                         entry = entry->q_next;
00325                 } while ( entry != hashbin->hb_queue[ bin ] );
00326         }
00327         
00328         /* Release lock */
00329         if ( hashbin->hb_type & HB_GLOBAL) {
00330                 spin_unlock_irq( &hashbin->hb_mutex[ bin]);
00331 
00332         } else if ( hashbin->hb_type & HB_LOCAL) {
00333                 restore_flags( flags);
00334         }
00335         
00336         if ( found ) 
00337                 return entry;
00338         else
00339                 return NULL;
00340 }
00341 
00342 void *hashbin_remove_first( hashbin_t *hashbin)
00343 {
00344         unsigned long flags;
00345         queue_t *entry = NULL;
00346 
00347         save_flags(flags);
00348         cli();
00349 
00350         entry = hashbin_get_first( hashbin);
00351         if ( entry != NULL)
00352                 hashbin_remove( hashbin, entry->q_hash, NULL);
00353 
00354         restore_flags( flags);
00355 
00356         return entry;
00357 }
00358 
00359 
00360 /* 
00361  *  Function hashbin_remove (hashbin, hashv, name)
00362  *
00363  *    Remove entry with the given name
00364  *
00365  */
00366 void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name)
00367 {
00368         int bin, found = FALSE;
00369         unsigned long flags = 0;
00370         queue_t* entry;
00371 
00372         IRDA_DEBUG( 4, __FUNCTION__ "()\n");
00373 
00374         ASSERT( hashbin != NULL, return NULL;);
00375         ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
00376         
00377         /*
00378          * Locate hashbin
00379          */
00380         if ( name )
00381                 hashv = hash( name );
00382         bin = GET_HASHBIN( hashv );
00383 
00384         if ( hashbin->hb_type & HB_GLOBAL ) {
00385                 spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
00386 
00387         } else if ( hashbin->hb_type & HB_LOCAL ) {
00388                 save_flags(flags);
00389                 cli();
00390         } /* Default is no-lock  */
00391 
00392         /*
00393          * Search for entry
00394          */
00395         entry = hashbin->hb_queue[ bin ];
00396         if ( entry ) {
00397                 do {
00398                         /*
00399                          * Check for key
00400                          */
00401                         if ( entry->q_hash == hashv ) {
00402                                 /*
00403                                  * Name compare too?
00404                                  */
00405                                 if ( name ) {
00406                                         if ( strcmp( entry->q_name, name) == 0)
00407                                         {
00408                                                 found = TRUE;
00409                                                 break;
00410                                         }
00411                                 } else {
00412                                         found = TRUE;
00413                                         break;
00414                                 }
00415                         }
00416                         entry = entry->q_next;
00417                 } while ( entry != hashbin->hb_queue[ bin ] );
00418         }
00419         
00420         /*
00421          * If entry was found, dequeue it
00422          */
00423         if ( found ) {
00424                 dequeue_general( (queue_t**) &hashbin->hb_queue[ bin ],
00425                                  (queue_t*) entry );
00426                 hashbin->hb_size--;
00427 
00428                 /*
00429                  *  Check if this item is the currently selected item, and in
00430                  *  that case we must reset hb_current
00431                  */
00432                 if ( entry == hashbin->hb_current)
00433                         hashbin->hb_current = NULL;
00434         }
00435 
00436         /* Release lock */
00437         if ( hashbin->hb_type & HB_GLOBAL) {
00438                 spin_unlock_irq( &hashbin->hb_mutex[ bin]);
00439 
00440         } else if ( hashbin->hb_type & HB_LOCAL) {
00441                 restore_flags( flags);
00442         }
00443        
00444         
00445         /* Return */
00446         if ( found ) 
00447                 return entry;
00448         else
00449                 return NULL;
00450         
00451 }
00452 
00453 /*
00454  * Function hashbin_get_first (hashbin)
00455  *
00456  *    Get a pointer to first element in hashbin, this function must be
00457  *    called before any calls to hashbin_get_next()!
00458  *
00459  */
00460 queue_t *hashbin_get_first( hashbin_t* hashbin) 
00461 {
00462         queue_t *entry;
00463         int i;
00464 
00465         ASSERT( hashbin != NULL, return NULL;);
00466         ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
00467 
00468         if ( hashbin == NULL)
00469                 return NULL;
00470 
00471         for ( i = 0; i < HASHBIN_SIZE; i ++ ) {
00472                 entry = hashbin->hb_queue[ i];
00473                 if ( entry) {
00474                         hashbin->hb_current = entry;
00475                         return entry;
00476                 }
00477         }
00478         /*
00479          *  Did not find any item in hashbin
00480          */
00481         return NULL;
00482 }
00483 
00484 /*
00485  * Function hashbin_get_next (hashbin)
00486  *
00487  *    Get next item in hashbin. A series of hashbin_get_next() calls must
00488  *    be started by a call to hashbin_get_first(). The function returns
00489  *    NULL when all items have been traversed
00490  * 
00491  */
00492 queue_t *hashbin_get_next( hashbin_t *hashbin)
00493 {
00494         queue_t* entry;
00495         int bin;
00496         int i;
00497 
00498         ASSERT( hashbin != NULL, return NULL;);
00499         ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
00500 
00501         if ( hashbin->hb_current == NULL) {
00502                 ASSERT( hashbin->hb_current != NULL, return NULL;);
00503                 return NULL;
00504         }       
00505         entry = hashbin->hb_current->q_next;
00506         bin = GET_HASHBIN( entry->q_hash);
00507 
00508         /*  
00509          *  Make sure that we are not back at the beginning of the queue
00510          *  again 
00511          */
00512         if ( entry != hashbin->hb_queue[ bin ]) {
00513                 hashbin->hb_current = entry;
00514 
00515                 return entry;
00516         }
00517 
00518         /*
00519          *  Check that this is not the last queue in hashbin
00520          */
00521         if ( bin >= HASHBIN_SIZE)
00522                 return NULL;
00523         
00524         /*
00525          *  Move to next queue in hashbin
00526          */
00527         bin++;
00528         for ( i = bin; i < HASHBIN_SIZE; i++ ) {
00529                 entry = hashbin->hb_queue[ i];
00530                 if ( entry) {
00531                         hashbin->hb_current = entry;
00532                         
00533                         return entry;
00534                 }
00535         }
00536         return NULL;
00537 }
00538 
00539 /*
00540  * Function enqueue_last (queue, proc)
00541  *
00542  *    Insert item into end of queue.
00543  *
00544  */
00545 static void __enqueue_last( queue_t **queue, queue_t* element)
00546 {
00547         IRDA_DEBUG( 4, __FUNCTION__ "()\n");
00548 
00549         /*
00550          * Check if queue is empty.
00551          */
00552         if ( *queue == NULL ) {
00553                 /*
00554                  * Queue is empty.  Insert one element into the queue.
00555                  */
00556                 element->q_next = element->q_prev = *queue = element;
00557                 
00558         } else {
00559                 /*
00560                  * Queue is not empty.  Insert element into end of queue.
00561                  */
00562                 element->q_prev         = (*queue)->q_prev;
00563                 element->q_prev->q_next = element;
00564                 (*queue)->q_prev        = element;
00565                 element->q_next         = *queue;
00566         }       
00567 }
00568 
00569 inline void enqueue_last( queue_t **queue, queue_t* element)
00570 {
00571         unsigned long flags;
00572         
00573         save_flags(flags);
00574         cli();
00575 
00576         __enqueue_last( queue, element);
00577 
00578         restore_flags(flags);
00579 }
00580 
00581 /*
00582  * Function enqueue_first (queue, proc)
00583  *
00584  *    Insert item first in queue.
00585  *
00586  */
00587 void enqueue_first(queue_t **queue, queue_t* element)
00588 {
00589         
00590         IRDA_DEBUG( 4, __FUNCTION__ "()\n");
00591 
00592         /*
00593          * Check if queue is empty.
00594          */
00595         if ( *queue == NULL ) {
00596                 /*
00597                  * Queue is empty.  Insert one element into the queue.
00598                  */
00599                 element->q_next = element->q_prev = *queue = element;
00600                 
00601         } else {
00602                 /*
00603                  * Queue is not empty.  Insert element into front of queue.
00604                  */
00605                 element->q_next          = (*queue);
00606                 (*queue)->q_prev->q_next = element;
00607                 element->q_prev          = (*queue)->q_prev;
00608                 (*queue)->q_prev         = element;
00609                 (*queue)                 = element;
00610         }
00611 }
00612 
00613 /*
00614  * Function enqueue_queue (queue, list)
00615  *
00616  *    Insert a queue (list) into the start of the first queue
00617  *
00618  */
00619 void enqueue_queue( queue_t** queue, queue_t** list )
00620 {
00621         queue_t* tmp;
00622         
00623         /*
00624          * Check if queue is empty
00625          */ 
00626         if ( *queue ) {
00627                 (*list)->q_prev->q_next  = (*queue);
00628                 (*queue)->q_prev->q_next = (*list); 
00629                 tmp                      = (*list)->q_prev;
00630                 (*list)->q_prev          = (*queue)->q_prev;
00631                 (*queue)->q_prev         = tmp;
00632         } else {
00633                 *queue                   = (*list); 
00634         }
00635         
00636         (*list) = NULL;
00637 }
00638 
00639 /*
00640  * Function enqueue_second (queue, proc)
00641  *
00642  *    Insert item behind head of queue.
00643  *
00644  */
00645 #if 0
00646 static void enqueue_second(queue_t **queue, queue_t* element)
00647 {
00648         IRDA_DEBUG( 0, "enqueue_second()\n");
00649 
00650         /*
00651          * Check if queue is empty.
00652          */
00653         if ( *queue == NULL ) {
00654                 /*
00655                  * Queue is empty.  Insert one element into the queue.
00656                  */
00657                 element->q_next = element->q_prev = *queue = element;
00658                 
00659         } else {
00660                 /*
00661                  * Queue is not empty.  Insert element into ..
00662                  */
00663                 element->q_prev = (*queue);
00664                 (*queue)->q_next->q_prev = element;
00665                 element->q_next = (*queue)->q_next;
00666                 (*queue)->q_next = element;
00667         }
00668 }
00669 #endif
00670 
00671 /*
00672  * Function dequeue (queue)
00673  *
00674  *    Remove first entry in queue
00675  *
00676  */
00677 queue_t *dequeue_first(queue_t **queue)
00678 {
00679         queue_t *ret;
00680 
00681         IRDA_DEBUG( 4, "dequeue_first()\n");
00682         
00683         /*
00684          * Set return value
00685          */
00686         ret =  *queue;
00687         
00688         if ( *queue == NULL ) {
00689                 /*
00690                  * Queue was empty.
00691                  */
00692         } else if ( (*queue)->q_next == *queue ) {
00693                 /* 
00694                  *  Queue only contained a single element. It will now be
00695                  *  empty.  
00696                  */
00697                 *queue = NULL;
00698         } else {
00699                 /*
00700                  * Queue contained several element.  Remove the first one.
00701                  */
00702                 (*queue)->q_prev->q_next = (*queue)->q_next;
00703                 (*queue)->q_next->q_prev = (*queue)->q_prev;
00704                 *queue = (*queue)->q_next;
00705         }
00706         
00707         /*
00708          * Return the removed entry (or NULL of queue was empty).
00709          */
00710         return ret;
00711 }
00712 
00713 /*
00714  * Function dequeue_general (queue, element)
00715  *
00716  *
00717  */
00718 static queue_t *dequeue_general(queue_t **queue, queue_t* element)
00719 {
00720         queue_t *ret;
00721         
00722         IRDA_DEBUG( 4, "dequeue_general()\n");
00723         
00724         /*
00725          * Set return value
00726          */
00727         ret =  *queue;
00728                 
00729         if ( *queue == NULL ) {
00730                 /*
00731                  * Queue was empty.
00732                  */
00733         } if ( (*queue)->q_next == *queue ) {
00734                 /* 
00735                  *  Queue only contained a single element. It will now be
00736                  *  empty.  
00737                  */
00738                 *queue = NULL;
00739                 
00740         } else {
00741                 /*
00742                  *  Remove specific element.
00743                  */
00744                 element->q_prev->q_next = element->q_next;
00745                 element->q_next->q_prev = element->q_prev;
00746                 if ( (*queue) == element)
00747                         (*queue) = element->q_next;
00748         }
00749         
00750         /*
00751          * Return the removed entry (or NULL of queue was empty).
00752          */
00753         return ret;
00754 }
00755 
00756 /*
00757  * Function hash (name)
00758  *
00759  *    This function hash the input string 'name' using the ELF hash
00760  *    function for strings.
00761  */
00762 static __u32 hash( char* name)
00763 {
00764         __u32 h = 0;
00765         __u32 g;
00766         
00767         while(*name) {
00768                 h = (h<<4) + *name++;
00769                 if ((g = (h & 0xf0000000)))
00770                         h ^=g>>24;
00771                 h &=~g;
00772         }
00773         return h;
00774 }