Main Page | Directories | File List | Globals

hash_st.c

Go to the documentation of this file.
00001 /*
00002  * kernel_libs/data_structures/hash_st.c
00003  *
00004  * Copyright (c) 2003-2004 Lukasz Dembinski <dembol@nasa.com.pl>
00005  * All Rights Reserved
00006  * 
00007  * Date:        2004/01
00008  * Author:      Lukasz Dembinski
00009  * Info:        hash_st.c core file, hashing with open addressing
00010  * Contact:     mailto: <dembol@nasa.com.pl>
00011  * 
00012  */
00013 
00014 #include <agnix/agnix.h>
00015 #include <agnix/init.h>
00016 #include <agnix/memory.h>
00017 #include <agnix/list.h>
00018 #include <agnix/errno.h>
00019 #include <agnix/spinlock.h>
00020 #include <agnix/console.h>
00021 
00022 #define HASH_ENTRIES            ((PAGE_SIZE - sizeof(struct hash_table_s)) >> 3)
00023 #define MAX_HASH_TABLES         16
00024 #define MAX_HASH_ORDER          16
00025 
00026 #define PSEUDO_KEY_FREE         0
00027 #define PSEUDO_KEY_DELETED      1
00028 #define PSEUDO_KEY_BUSY         2
00029 
00030 #define find_hash_table(hashd) (&hash_tables[hashd])
00031 
00032 #define HASH_DEBUG              0
00033 #define MOD_NAME                "HASH: "
00034 
00035 struct hash_entry_s {
00036     u32 hash_key;
00037     u32 hash_addr;
00038     int hash_status;
00039 };
00040 
00041 struct hash_table_s {
00042     char *hash_name;
00043     int max_entries;
00044     int cur_entries;
00045     int page_order;
00046     int hashd;
00047 
00048     u32 (*hash_fn)(u32 key);
00049     struct hash_entry_s *hash_entry;
00050     spinlock_t hash_lock;
00051 };
00052 
00053 struct hash_table_s hash_tables[MAX_HASH_TABLES];
00054 
00055 u32 hash_fn_default(u32 key)
00056 {
00057     return key;
00058 }
00059 
00060 u32 hash_math_pseudo(struct hash_table_s *hash_table_ptr, u32 hash_key)
00061 {
00062     if (hash_table_ptr->hash_fn)
00063         return hash_table_ptr->hash_fn(hash_key);
00064     else
00065         return hash_key;
00066 }
00067 
00068 void hash_count_entries(int hashd) 
00069 {
00070     struct hash_table_s *hash_table_ptr;    
00071 
00072     hash_table_ptr = find_hash_table(hashd);
00073     printk("hash_ptr %x\n", hash_table_ptr);
00074     printk("hash_max_entries %x\n", hash_table_ptr->max_entries);
00075     printk("hash_cur_entries %x\n", hash_table_ptr->cur_entries);
00076 }
00077 
00078 int hash_entry_add(int hashd, u32 hash_key, u32 hash_addr)
00079 {
00080     struct hash_table_s *hash_table_ptr;
00081     struct hash_entry_s *hash_entry;
00082     u32 pseudo_key = 0;
00083     int loops;
00084     u32 flags;
00085 
00086     spin_lock_irqsave(&hash_table_ptr->hash_lock, flags);
00087 
00088     hash_table_ptr = find_hash_table(hashd);
00089 
00090     if (!hash_table_ptr->max_entries)
00091         return -1;
00092 
00093     hash_entry = hash_table_ptr->hash_entry;
00094     pseudo_key = hash_math_pseudo(hash_table_ptr, hash_key) % hash_table_ptr->max_entries;
00095 
00096     loops = 0;
00097     do {
00098         if (hash_entry[pseudo_key].hash_status == PSEUDO_KEY_BUSY) {
00099             pseudo_key = (pseudo_key + 1) % hash_table_ptr->max_entries;
00100         } else {
00101             hash_entry[pseudo_key].hash_key    = hash_key;
00102             hash_entry[pseudo_key].hash_addr   = hash_addr;
00103             hash_entry[pseudo_key].hash_status = PSEUDO_KEY_BUSY;
00104             hash_table_ptr->cur_entries++;
00105             spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00106             return 0;
00107         }
00108         
00109         loops++;
00110         
00111     } while(loops < hash_table_ptr->max_entries);
00112         
00113     spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00114     
00115     return -1;   
00116 }
00117 
00118 int hash_entry_del(int hashd, u32 hash_key)
00119 {
00120     struct hash_table_s *hash_table_ptr;
00121     struct hash_entry_s *hash_entry;
00122     u32 pseudo_key = 0;
00123     int loops;
00124     u32 flags;
00125 
00126     spin_lock_irqsave(&hash_table_ptr->hash_lock, flags);
00127 
00128     hash_table_ptr = find_hash_table(hashd);
00129     if (!hash_table_ptr->max_entries)
00130         return -1;
00131 
00132     hash_entry = hash_table_ptr->hash_entry;
00133     pseudo_key = hash_math_pseudo(hash_table_ptr, hash_key) % hash_table_ptr->max_entries;
00134 
00135     loops = 0;
00136     do {
00137         
00138         if (hash_entry[pseudo_key].hash_status == PSEUDO_KEY_FREE) {
00139             break;
00140         }
00141     
00142         if ((hash_entry[pseudo_key].hash_status != PSEUDO_KEY_BUSY) || 
00143             ((u32)hash_entry[pseudo_key].hash_key != (u32)hash_key)) {
00144             pseudo_key = (pseudo_key + 1) % hash_table_ptr->max_entries;
00145         }
00146         else {   
00147             hash_entry[pseudo_key].hash_status = PSEUDO_KEY_DELETED;    
00148             spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00149             return 0;
00150         }
00151         
00152         loops++;
00153         
00154     } while(loops < hash_table_ptr->max_entries);
00155     
00156     spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00157     return -1;   
00158 }
00159 
00160 u32 hash_entry_find(int hashd, u32 hash_key)
00161 {
00162     struct hash_table_s *hash_table_ptr;
00163     struct hash_entry_s *hash_entry;
00164     u32 pseudo_key = 0;
00165     int loops;
00166     u32 flags;
00167     
00168     spin_lock_irqsave(&hash_table_ptr->hash_lock, flags);
00169     
00170     hash_table_ptr = find_hash_table(hashd);
00171     if (!hash_table_ptr->max_entries)
00172         return 0;
00173 
00174     hash_entry = hash_table_ptr->hash_entry;
00175     pseudo_key = hash_math_pseudo(hash_table_ptr, hash_key) % hash_table_ptr->max_entries;
00176 
00177     loops = 0;    
00178     do {
00179         if (hash_entry[pseudo_key].hash_status == PSEUDO_KEY_FREE)
00180             break;
00181             
00182         if ((hash_entry[pseudo_key].hash_status != PSEUDO_KEY_BUSY) || 
00183             ((u32)hash_entry[pseudo_key].hash_key != (u32)hash_key)) {
00184             pseudo_key = (pseudo_key + 1) % hash_table_ptr->max_entries;
00185         }
00186         else {   
00187 
00188             spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00189             return hash_entry[pseudo_key].hash_addr;
00190         }
00191         
00192         loops++;
00193         
00194     } while(loops < hash_table_ptr->max_entries);
00195     
00196     spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00197     
00198     return 0;
00199 }
00200 
00201 static int get_empty_hash_table(void)
00202 {
00203     u32 flags;
00204     int i;
00205     
00206     for (i = 0; i < MAX_HASH_TABLES; i++) {
00207         spin_lock_irqsave(&hash_tables[i].hash_lock, flags);
00208         if (!hash_tables[i].cur_entries &&
00209             !hash_tables[i].max_entries) {
00210                 spin_unlock_irqrestore(&hash_tables[i].hash_lock, flags);
00211                 return i;
00212         }
00213             
00214         spin_unlock_irqrestore(&hash_tables[i].hash_lock, flags);
00215     }
00216     
00217     return -1;
00218 }
00219 
00220 static void put_empty_hash_table(int hashd)
00221 {
00222     u32 flags;
00223 
00224     spin_lock_irqsave(&hash_tables[hashd].hash_lock, flags);
00225     memset(&hash_tables[hashd], 0, sizeof(struct hash_table_s));
00226     spin_unlock_irqrestore(&hash_tables[hashd].hash_lock, flags);
00227 }
00228 
00229 int register_hash_table(char *name, u32 rows, u32 (*hash_fn)(u32 key))
00230 {
00231     struct hash_table_s *hash_table;
00232     struct hash_entry_s *hash_entry;
00233     int page_order = 0;  
00234     int hashd;  
00235     int i;
00236 
00237     hashd = get_empty_hash_table();
00238     if (hashd == -1)
00239         return -EAGAIN;
00240 
00241     for (i = 0; i < MAX_HASH_ORDER; i++) {
00242         if (rows < (((1 << i) * PAGE_SIZE) / sizeof(struct hash_entry_s))) {
00243             page_order = i;
00244             break;
00245         }
00246     }
00247 
00248     if (i == MAX_HASH_ORDER)
00249         return -EINVAL;
00250 
00251     hash_table = &hash_tables[hashd];
00252     hash_entry = (struct hash_entry_s *)get_free_pages(page_order);
00253     
00254     if (!hash_table) {
00255         put_empty_hash_table(hashd);
00256         return -ENOMEM;
00257     }
00258 
00259     if (hash_fn)
00260         hash_table->hash_fn = hash_fn;
00261     else
00262         hash_table->hash_fn = hash_fn_default;
00263 
00264     hash_table->hash_name   = name;
00265     hash_table->max_entries = ((1 << page_order) * PAGE_SIZE) / sizeof(struct hash_entry_s);
00266     hash_table->cur_entries = 0;
00267     hash_table->page_order  = page_order;
00268     hash_table->hashd       = hashd;        
00269     hash_table->hash_entry  = hash_entry;
00270     
00271     for (i = 0; i < hash_table->max_entries; i++)
00272         hash_table->hash_entry[i].hash_status = PSEUDO_KEY_FREE;
00273     
00274 #if HASH_DEBUG
00275     printk(MOD_NAME "registering %s hashing table (%d rows/%d pages)\n", name, hash_table->max_entries, page_order);
00276 #endif
00277 
00278     spin_lock_init(&hash_table->hash_lock);
00279     
00280     return hashd;
00281 }
00282 
00283 int unregister_hash_table(int hashd)
00284 {
00285     struct hash_table_s *hash_table_ptr;    
00286 
00287     hash_table_ptr = find_hash_table(hashd);
00288 
00289     if (hash_table_ptr) {
00290         put_free_pages((u32)hash_table_ptr->hash_entry, (u8)(hash_table_ptr->page_order));
00291         put_free_pages((u32)hash_table_ptr, 0);
00292     }
00293 
00294     return 0;
00295 }
00296 
00297 int hash_static_init(void)
00298 {
00299     int i;
00300 
00301     for (i = 0; i < MAX_HASH_TABLES; i++) {
00302         memset((void *)&hash_tables[i], 0, sizeof(struct hash_table_s));
00303     }
00304 
00305     return 0;
00306 }
00307 
Dokumentacje wygenerowano programem Doxygen 1.4.2 dla projektu Agnix