collection.c

00001 #include <stdlib.h>
00002 #include <string.h>
00003 #include "collection.h"
00004 
00005 cp_wrap *cp_wrap_new(void *item, cp_destructor_fn dtr)
00006 {
00007     cp_wrap *wrap = calloc(1, sizeof(cp_wrap));
00008     if (wrap)
00009     {
00010         wrap->item = item;
00011         wrap->dtr = dtr;
00012     }
00013 
00014     return wrap;
00015 }
00016 
00017 void cp_wrap_delete(cp_wrap *wrap)
00018 {
00019     if (wrap)
00020     {
00021         if (wrap->dtr)
00022             (*wrap->dtr)(wrap->item);
00023 
00024         free(wrap);
00025     }
00026 }
00027 
00028 cp_mapping *cp_mapping_create(void *key, void *value)
00029 {
00030     cp_mapping *m = (cp_mapping *) malloc(sizeof(cp_mapping));
00031     if (m)
00032     {
00033         m->key = key;
00034         m->value = value;
00035     }
00036     return m;
00037 }
00038 
00039 cp_index *cp_index_create(cp_index_type type, cp_key_fn key, cp_compare_fn cmp)
00040 {
00041     cp_index *i = (cp_index *) malloc(sizeof(cp_index));
00042     if (i)
00043     {
00044         i->type = type;
00045         i->key = key;
00046         i->cmp = cmp;
00047     }
00048     return i;
00049 }
00050 
00051 cp_index *cp_index_copy(cp_index *src)
00052 {
00053     cp_index *i = (cp_index *) malloc(sizeof(cp_index));
00054     if (i) memcpy(i, src, sizeof(cp_index));
00055     return i;
00056 }
00057 
00058 int cp_index_compare(cp_index *index, void *a, void *b)
00059 {
00060     return index->key ? 
00061         (*index->cmp)((*index->key)(a), (*index->key)(b)) : 
00062         (*index->cmp)(a, b);
00063 }
00064 
00065 #ifdef _WINDOWS
00066 BOOL APIENTRY DllMain( HANDLE hModule, 
00067                        DWORD  ul_reason_for_call, 
00068                        LPVOID lpReserved
00069                      )
00070 {
00071     switch (ul_reason_for_call)
00072     {
00073         case DLL_PROCESS_ATTACH:
00074         case DLL_THREAD_ATTACH:
00075         case DLL_THREAD_DETACH:
00076         case DLL_PROCESS_DETACH:
00077             break;
00078     }
00079     return TRUE;
00080 }
00081 
00082 /* WIN32 implementation of cp_mutex_init */
00083 int cp_mutex_init(cp_mutex *mutex, void *attr)
00084 { 
00085     *mutex = CreateMutex((attr), FALSE, NULL);
00086     return *mutex == NULL;
00087 }
00088 
00089 /* WIN32 implementation of read-write locks. cp_lock is not upgradeable. */
00090 
00091 int cp_lock_init(cp_lock *lock, void *attr)
00092 {
00093     SECURITY_ATTRIBUTES sec_attr;
00094     sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
00095     sec_attr.lpSecurityDescriptor = NULL;
00096     sec_attr.bInheritHandle = FALSE;
00097 
00098     lock->access_mutex = CreateMutex(&sec_attr, FALSE, NULL);
00099 //  lock->write_mutex = CreateMutex(&sec_attr, FALSE, NULL);
00100     lock->readers = 0;
00101     lock->writer = 0;
00102     lock->writer_waiting = 0;
00103 
00104     return 0;
00105 }
00106 
00107 int cp_lock_rdlock(cp_lock *lock)
00108 {
00109     while (1)
00110     {
00111         WaitForSingleObject(lock->access_mutex, INFINITE);
00112         if (lock->writer_waiting)
00113             ReleaseMutex(lock->access_mutex);
00114         else
00115             break;
00116     }
00117     lock->readers++;
00118     ReleaseMutex(lock->access_mutex);
00119 
00120     return 0;
00121 }
00122 
00123 int cp_lock_wrlock(cp_lock *lock)
00124 {
00125     if (lock->writer == GetCurrentThreadId()) return 0;
00126 
00127     while (1)
00128     {
00129         WaitForSingleObject(lock->access_mutex, INFINITE);
00130         lock->writer_waiting = 1;
00131         if (lock->readers)
00132             ReleaseMutex(lock->access_mutex);
00133         else
00134             break;
00135     }
00136 
00137     lock->writer = GetCurrentThreadId();
00138     lock->writer_waiting = 0;
00139 
00140     return 0;
00141 }
00142 
00143 int cp_lock_unlock(cp_lock *lock)
00144 {
00145     if (lock->writer == GetCurrentThreadId())
00146         lock->writer = 0;
00147     else
00148     {
00149         WaitForSingleObject(lock->access_mutex, INFINITE);
00150         lock->readers--;
00151     }
00152 
00153     ReleaseMutex(lock->access_mutex);
00154     return 0;
00155 }
00156 
00157 int cp_lock_destroy(cp_lock *lock)
00158 {
00159     CloseHandle(lock->access_mutex);
00160     return 0;
00161 }
00162 
00163 /* WIN32 implementation of a basic POSIX-condition-variable-like API
00164  * 
00165  * based on "Strategies for Implementing POSIX Condition Variables on WIN32"
00166  * by Douglas C. Schmidt and Irfan Pyarali - 
00167  * see http://www.cs.wustl.edu/~schmidt/WIN32-cv-1.html
00168  */
00169 int cp_cond_init(cp_cond *cv, const void *attr) // pthread_condattr_t *)
00170 {
00171   cv->waiters_count_ = 0;
00172   cv->was_broadcast_ = 0;
00173   cv->sema_ = CreateSemaphore (NULL,       // no security
00174                                0,          // initially 0
00175                                0x7fffffff, // max count
00176                                NULL);      // unnamed 
00177   if (cv->sema_ == NULL) return -1;
00178   InitializeCriticalSection (&cv->waiters_count_lock_);
00179   cv->waiters_done_ = CreateEvent (NULL,  // no security
00180                                    FALSE, // auto-reset
00181                                    FALSE, // non-signaled initially
00182                                    NULL); // unnamed
00183   if (cv->waiters_done_ == NULL) return -1;
00184 
00185   return 0;
00186 }
00187 
00188 int cp_cond_destroy(cp_cond *cv)
00189 {
00190     if (cv)
00191     {
00192         CloseHandle(cv->sema_);
00193         DeleteCriticalSection(&cv->waiters_count_lock_);
00194         CloseHandle(cv->waiters_done_);
00195         return 0;
00196     }
00197 
00198     return -1;
00199 }
00200 
00201 int cp_cond_wait(cp_cond *cv, cp_mutex *external_mutex)
00202 {
00203     int last_waiter;
00204 //printf(" <<< cond_wait: starting\n");
00205     // Avoid race conditions.
00206     EnterCriticalSection (&cv->waiters_count_lock_);
00207     cv->waiters_count_++;
00208     LeaveCriticalSection (&cv->waiters_count_lock_);
00209 
00210 //printf("cond: calling SignalObjectAndWait\n");
00211     // This call atomically releases the mutex and waits on the
00212     // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
00213     // are called by another thread.
00214     SignalObjectAndWait (*external_mutex, cv->sema_, INFINITE, FALSE);
00215 //printf("cond: popped wait\n");
00216 
00217     // Reacquire lock to avoid race conditions.
00218     EnterCriticalSection (&cv->waiters_count_lock_);
00219 
00220     // We're no longer waiting...
00221     cv->waiters_count_--;
00222 
00223     // Check to see if we're the last waiter after <pthread_cond_broadcast>.
00224     last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0;
00225 
00226     LeaveCriticalSection (&cv->waiters_count_lock_);
00227 
00228     // If we're the last waiter thread during this particular broadcast
00229     // then let all the other threads proceed.
00230     if (last_waiter)
00231     {
00232 //      printf("cond_wait: signaling waiters_done_\n");
00233         // This call atomically signals the <waiters_done_> event and waits until
00234         // it can acquire the <external_mutex>.  This is required to ensure fairness. 
00235         SignalObjectAndWait (cv->waiters_done_, *external_mutex, INFINITE, FALSE);
00236     }
00237     else
00238     {
00239 //      printf("cond_wait: grab external_mutex\n");
00240         // Always regain the external mutex since that's the guarantee we
00241         // give to our callers. 
00242         WaitForSingleObject(*external_mutex, INFINITE);
00243     }
00244 //printf(" >>> cond_wait: done\n");
00245     return 0;
00246 }
00247 
00248 int cp_cond_signal(cp_cond *cv)
00249 {
00250     int have_waiters;
00251 
00252     EnterCriticalSection (&cv->waiters_count_lock_);
00253 //printf("cp_cond_signal: %d waiters\n", cv->waiters_count_);
00254     have_waiters = cv->waiters_count_ > 0;
00255     LeaveCriticalSection (&cv->waiters_count_lock_);
00256 
00257     // If there aren't any waiters, then this is a no-op.  
00258     if (have_waiters)
00259         ReleaseSemaphore (cv->sema_, 1, 0);
00260 
00261     return 0;
00262 }
00263 
00264 int cp_cond_broadcast(cp_cond *cv)
00265 {
00266     int have_waiters;
00267     // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
00268     // consistent relative to each other.
00269     EnterCriticalSection (&cv->waiters_count_lock_);
00270     have_waiters = 0;
00271 //printf("cp_cond_broadcast: %d waiters\n", cv->waiters_count_);
00272     if (cv->waiters_count_ > 0) {
00273         // We are broadcasting, even if there is just one waiter...
00274         // Record that we are broadcasting, which helps optimize
00275         // <pthread_cond_wait> for the non-broadcast case.
00276         cv->was_broadcast_ = 1;
00277         have_waiters = 1;
00278     }
00279 
00280     if (have_waiters) {
00281         // Wake up all the waiters atomically.
00282         ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0);
00283 
00284         LeaveCriticalSection (&cv->waiters_count_lock_);
00285 
00286         // Wait for all the awakened threads to acquire the counting
00287         // semaphore. 
00288         WaitForSingleObject (cv->waiters_done_, INFINITE);
00289         // This assignment is okay, even without the <waiters_count_lock_> held 
00290         // because no other waiter threads can wake up to access it.
00291         cv->was_broadcast_ = 0;
00292     }
00293     else
00294         LeaveCriticalSection (&cv->waiters_count_lock_);
00295 
00296     return 0;
00297 }
00298 
00299 void *cp_calloc(size_t count, size_t size)
00300 {
00301     return calloc(count, size);
00302 }
00303 
00304 void *cp_realloc(void *p, size_t size)
00305 {
00306     return realloc(p, size);
00307 }
00308 
00309 void *cp_malloc(size_t size)
00310 {
00311     return malloc(size);
00312 }
00313 
00314 void cp_free(void *p)
00315 {
00316     free(p);
00317 }
00318 #endif /* _WINDOWS */

Generated on Mon Dec 5 23:00:21 2011 for cprops by  doxygen 1.4.7