usermode/library/malloc-original/src/arch-specific.cpp

00001 
00002 //
00003 // The Hoard Multiprocessor Memory Allocator
00004 // www.hoard.org
00005 //
00006 // Author: Emery Berger, http://www.cs.utexas.edu/users/emery
00007 //
00008 // Copyright (c) 1998-2001, The University of Texas at Austin.
00009 //
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Library General Public License as
00012 // published by the Free Software Foundation, http://www.fsf.org.
00013 //
00014 // This library is distributed in the hope that it will be useful, but
00015 // WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Library General Public License for more details.
00018 //
00020 
00021 
00022 #include "arch-specific.h"
00023 
00024 // How many iterations we spin waiting for a lock.
00025 enum { SPIN_LIMIT = 100 };
00026 
00027 // The values of a user-level lock.
00028 enum { UNLOCKED = 0, LOCKED = 1 };
00029 
00030 extern "C" {
00031 
00032 #ifdef WIN32
00033 
00034 unsigned long hoardInterlockedExchange (unsigned long * oldval,
00035                                         unsigned long newval)
00036 {
00037   return InterlockedExchange (reinterpret_cast<long *>(oldval), newval);
00038 }
00039 
00040 void hoardCreateThread (hoardThreadType& t,
00041                         void *(*function) (void *),
00042                         void * arg)
00043 {
00044   t = CreateThread (0, 0, (LPTHREAD_START_ROUTINE) function, (LPVOID) arg, 0, 0);
00045 }
00046 
00047 void hoardJoinThread (hoardThreadType& t)
00048 {
00049   WaitForSingleObject (t, INFINITE);
00050 }
00051 
00052 void hoardSetConcurrency (int)
00053 {
00054 }
00055 
00056 int hoardGetThreadID (void) {
00057   // Windows thread id's are even, so we divide them by two
00058   // in order to get a reasonable thread identifier.
00059   int tid = GetCurrentThreadId() >> 1;
00060   return tid;
00061 }
00062 
00063 void hoardLockInit (hoardLockType& mutex) {
00064         mutex = UNLOCKED;
00065         //  InitializeCriticalSection (&mutex);
00066 }
00067 
00068 void hoardLock (hoardLockType& mutex) {
00069 #if 0
00070   int spincount = 0;
00071   while (InterlockedExchange (&mutex, LOCKED) != UNLOCKED) {
00072     spincount++;
00073     if (spincount > 100) {
00074       hoardYield();
00075       spincount = 0;
00076     }
00077   }
00078 #else
00079         while (InterlockedExchange (&mutex, LOCKED) != UNLOCKED) {
00080                 hoardYield();
00081         }
00082 #endif
00083 //      EnterCriticalSection (&mutex);
00084 }
00085 
00086 void hoardYield (void) {
00087   Sleep (0);
00088 }
00089 
00090 void hoardUnlock (hoardLockType& mutex) {
00091         mutex = UNLOCKED;
00092 //      LeaveCriticalSection(&mutex);
00093 }
00094 
00095 #if 0
00096 void hoardLockDestroy (hoardLockType& mutex) {
00097 //      DeleteCriticalSection(&mutex);
00098 }
00099 #endif
00100 
00101 static hoardLockType memoryLock = UNLOCKED;
00102 extern "C" void * dlmalloc (size_t);
00103 extern "C" void dlfree (void *);
00104 
00105 void * hoardGetMemory (long size)
00106 {
00107 #if 0
00108         hoardLock (memoryLock);
00109   void * ptr = dlmalloc (size);
00110         hoardUnlock (memoryLock);
00111 #else
00112   void * ptr = HeapAlloc (GetProcessHeap(), 0, size);
00113 #endif
00114 
00115   return (void *) ptr;
00116 }
00117 
00118 
00119 void hoardFreeMemory (void * ptr)
00120 {
00121 #if 0
00122         hoardLock (memoryLock);
00123         dlfree (ptr);
00124         hoardUnlock (memoryLock);
00125 #else
00126         HeapFree (GetProcessHeap(), 0, ptr);
00127 #endif
00128 }
00129 
00130 int hoardGetPageSize (void)
00131 {
00132   SYSTEM_INFO infoReturn[1];
00133   GetSystemInfo (infoReturn);
00134   return (int) (infoReturn -> dwPageSize);
00135 }
00136 
00137 
00138 int hoardGetNumProcessors (void)
00139 {
00140   static int numProcessors = 0;
00141   if (numProcessors == 0) {
00142     SYSTEM_INFO infoReturn[1];
00143     GetSystemInfo (infoReturn);
00144     numProcessors = (int) (infoReturn -> dwNumberOfProcessors);
00145   }
00146   return numProcessors;
00147 }
00148 
00149 #else // UNIX
00150 
00151 #if USE_SPROC
00152 #include <sys/types.h>
00153 #include <sys/wait.h>
00154 #include <unistd.h>
00155 #include <ulocks.h>
00156 #endif
00157 
00158 void hoardCreateThread (hoardThreadType& t,
00159                         void *(*function) (void *),
00160                         void * arg)
00161 {
00162 #if USE_SPROC
00163   typedef void (*sprocFunction) (void *);
00164   t = sproc ((sprocFunction) function, PR_SADDR, arg);
00165 #else
00166   pthread_attr_t attr;
00167   pthread_attr_init (&attr);
00168 #if defined(_AIX)
00169   // Bound (kernel-level) threads.
00170   pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
00171 #endif
00172   pthread_create (&t, &attr, function, arg);
00173 #endif
00174 }
00175 
00176 void hoardJoinThread (hoardThreadType& t)
00177 {
00178 #if USE_SPROC
00179   waitpid (t, 0, 0);
00180 #else
00181   pthread_join (t, NULL);
00182 #endif
00183 }
00184 
00185 #if 0 // DISABLED!
00186 #if defined(__linux)
00187 // This extern declaration is required for some versions of Linux.
00188 extern "C" void pthread_setconcurrency (int n);
00189 #endif
00190 #endif
00191 
00192 void hoardSetConcurrency (int n)
00193 {
00194 #if USE_SPROC
00195   usconfig (CONF_INITUSERS, n);
00196 #elif defined(__SVR4) // Solaris
00197   thr_setconcurrency (n);
00198 #else
00199   pthread_setconcurrency (n);
00200 #endif
00201 }
00202 
00203 
00204 #if defined(__SVR4) // Solaris
00205 
00206 // Solaris's two-level threads model gives us an edge here;
00207 // we can hash on the LWP's id. This helps us in two ways:
00208 // (1) there are likely to be far fewer LWP's than threads,
00209 // (2) if there's a one-to-one correspondence between LWP's
00210 //     and the number of processors (usually the case), then
00211 //     the number of heaps used will be the same as the number
00212 //     of processors (the optimal case).
00213 // Here we rely on an undocumented call in libthread.so, which
00214 // turns out to be MUCH cheaper than the documented _lwp_self(). Go figure.
00215 
00216 extern "C" unsigned int lwp_self(void);
00217 #endif
00218 
00219 int hoardGetThreadID (void) {
00220 #if USE_SPROC
00221   // This hairiness has the same effect as calling getpid(),
00222   // but it's MUCH faster since it avoids making a system call
00223   // and just accesses the sproc-local data directly.
00224   int pid = (int) PRDA->sys_prda.prda_sys.t_pid;
00225   return pid;
00226 #else
00227 #if defined(__linux)
00228   // Consecutive thread id's in Linux are 1024 apart.
00229   return (int) pthread_self() / 1024;
00230 #endif
00231 #if defined(__AIX)
00232   // Consecutive thread id's in AIX are 257 apart.
00233   return (int) pthread_self() / 257;
00234 #endif
00235 #if defined(__SVR4)
00236   return (int) lwp_self();
00237 #endif
00238   return (int) pthread_self();
00239 #endif
00240 }
00241 
00242 
00243 // Here's our own lock implementation (spin then yield). This is much
00244 // cheaper than the ordinary mutex, at least on Linux and Solaris.
00245 
00246 #if USER_LOCKS
00247 
00248 #include <sched.h>
00249 
00250 #if defined(__sgi)
00251 #include <mutex.h>
00252 #endif
00253 
00254 
00255 // Atomically:
00256 //   retval = *oldval;
00257 //   *oldval = newval;
00258 //   return retval;
00259 
00260 #if defined(sparc) && !defined(__GNUC__)
00261 extern "C" unsigned long InterlockedExchange (unsigned long * oldval,
00262                                               unsigned long newval);
00263 #else
00264 unsigned long InterlockedExchange (unsigned long * oldval,
00265                                                  unsigned long newval)
00266 {
00267 #if defined(sparc)
00268   asm volatile ("swap [%1],%0"
00269                 :"=r" (newval)
00270                 :"r" (oldval), "0" (newval)
00271                 : "memory");
00272 
00273 #endif
00274 #if defined(i386)
00275   asm volatile ("xchgl %0, %1"
00276                 : "=r" (newval)
00277                 : "m" (*oldval), "0" (newval)
00278                 : "memory");
00279 #endif
00280 #if defined(__sgi)
00281   newval = test_and_set (oldval, newval);
00282 #endif
00283 #if defined(ppc)
00284   int ret;
00285   asm volatile ("sync;"
00286                 "0:    lwarx %0,0,%1 ;"
00287                 "      xor. %0,%3,%0;"
00288                 "      bne 1f;"
00289                 "      stwcx. %2,0,%1;"
00290                 "      bne- 0b;"
00291                 "1:    sync"
00292         : "=&r"(ret)
00293         : "r"(oldval), "r"(newval), "r"(*oldval)
00294         : "cr0", "memory");
00295 #endif
00296 #if !(defined(sparc) || defined(i386) || defined(__sgi) || defined(ppc))
00297 #error "Hoard does not include support for user-level locks for this platform."
00298 #endif
00299   return newval;
00300 }
00301 #endif
00302 
00303 unsigned long hoardInterlockedExchange (unsigned long * oldval,
00304                                         unsigned long newval)
00305 {
00306   return InterlockedExchange (oldval, newval);
00307 }
00308 
00309 void hoardLockInit (hoardLockType& mutex) {
00310   InterlockedExchange (&mutex, UNLOCKED);
00311 }
00312 
00313 #include <stdio.h>
00314 
00315 void hoardLock (hoardLockType& mutex) {
00316   int spincount = 0;
00317   while (InterlockedExchange (&mutex, LOCKED) != UNLOCKED) {
00318     spincount++;
00319     if (spincount > 100) {
00320       hoardYield();
00321       spincount = 0;
00322     }
00323   }
00324 }
00325 
00326 void hoardUnlock (hoardLockType& mutex) {
00327         mutex = UNLOCKED;
00328 //  InterlockedExchange (&mutex, UNLOCKED);
00329 }
00330 
00331 #else
00332 
00333 // use non-user-level locks. 
00334 
00335 #endif // USER_LOCKS
00336 
00337 
00338 #if defined(__SVR4)
00339 #include <thread.h>
00340 #endif
00341 
00342 void hoardYield (void)
00343 {
00344 #if defined(__SVR4)
00345   thr_yield();
00346 #else
00347   sched_yield();
00348 #endif
00349 }
00350 
00351 
00352 extern "C" void * dlmalloc (size_t);
00353 extern "C" void dlfree (void *);
00354 
00355 
00356 #if USER_LOCKS
00357 static hoardLockType getMemoryLock = 0;
00358 #else
00359 static hoardLockType getMemoryLock = PTHREAD_MUTEX_INITIALIZER;
00360 #endif
00361 
00362 #include <stdio.h>
00363 
00364 void * hoardGetMemory (long size) {
00365   hoardLock (getMemoryLock);
00366   void * ptr = dlmalloc (size);
00367   hoardUnlock (getMemoryLock);
00368   return ptr;
00369 }
00370 
00371 
00372 void hoardFreeMemory (void * ptr)
00373 {
00374   hoardLock (getMemoryLock);
00375   dlfree (ptr);
00376   hoardUnlock (getMemoryLock);
00377 }
00378 
00379 
00380 int hoardGetPageSize (void)
00381 {
00382   return (int) sysconf(_SC_PAGESIZE);
00383 }
00384 
00385 
00386 #if defined(linux)
00387 #include <sys/types.h>
00388 #include <sys/stat.h>
00389 #include <fcntl.h>
00390 #include <string.h>
00391 #endif
00392 
00393 #if defined(__sgi)
00394 #include <sys/types.h>
00395 #include <sys/sysmp.h>
00396 #include <sys/sysinfo.h>
00397 #endif
00398 
00399 int hoardGetNumProcessors (void)
00400 {
00401 #if !(defined(linux))
00402 #if defined(__sgi)
00403   static int np = (int) sysmp(MP_NAPROCS);
00404   return np;
00405 #else
00406   static int np = (int) sysconf(_SC_NPROCESSORS_ONLN);
00407   return np;
00408 #endif
00409 #else
00410   static int numProcessors = 0;
00411 
00412   if (numProcessors == 0) {
00413     // Ugly workaround.  Linux's sysconf indirectly calls malloc() (at
00414     // least on multiprocessors).  So we just read the info from the
00415     // proc file ourselves and count the occurrences of the word
00416     // "processor".
00417     
00418     // We only parse the first 32K of the CPU file.  By my estimates,
00419     // that should be more than enough for at least 64 processors.
00420     enum { MAX_PROCFILE_SIZE = 32768 };
00421     char line[MAX_PROCFILE_SIZE];
00422     int fd = open ("/proc/cpuinfo", O_RDONLY);
00423     //    assert (fd);
00424     read(fd, line, MAX_PROCFILE_SIZE);
00425     char * str = line;
00426     while (str) {
00427       str = strstr(str, "processor");
00428       if (str) {
00429         numProcessors++;
00430         str++;
00431       }
00432     }
00433     close (fd);
00434     //    assert (numProcessors > 0);
00435   }
00436   return numProcessors;
00437 #endif
00438 }
00439 
00440 #endif // UNIX
00441 
00442 }

Generated on Sat Apr 23 11:43:35 2011 for Mnemosyne by  doxygen 1.4.7