usermode/library/pmalloc/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 #include <assert.h>
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 void hoardCreateThread (hoardThreadType& t,
00033                         void *(*function) (void *),
00034                         void * arg)
00035 {
00036   pthread_attr_t attr;
00037   pthread_attr_init (&attr);
00038   pthread_create (&t, &attr, function, arg);
00039 }
00040 
00041 void hoardJoinThread (hoardThreadType& t)
00042 {
00043   pthread_join (t, NULL);
00044 }
00045 
00046 #if 0 // DISABLED!
00047 #if defined(__linux)
00048 // This extern declaration is required for some versions of Linux.
00049 extern "C" void pthread_setconcurrency (int n);
00050 #endif
00051 #endif
00052 
00053 void hoardSetConcurrency (int n)
00054 {
00055   pthread_setconcurrency (n);
00056 }
00057 
00058 
00059 int hoardGetThreadID (void) {
00060   // Consecutive thread id's in Linux are 1024 apart.
00061   return (int) pthread_self() / 1024;
00062 }
00063 
00064 
00065 // Here's our own lock implementation (spin then yield). This is much
00066 // cheaper than the ordinary mutex, at least on Linux and Solaris.
00067 
00068 #if USER_LOCKS
00069 
00070 #include <sched.h>
00071 
00072 #if defined(__sgi)
00073 #include <mutex.h>
00074 #endif
00075 
00076 
00077 // Atomically:
00078 //   retval = *oldval;
00079 //   *oldval = newval;
00080 //   return retval;
00081 
00082 #if defined(sparc) && !defined(__GNUC__)
00083 extern "C" unsigned long InterlockedExchange (unsigned long * oldval,
00084                                               unsigned long newval);
00085 #else
00086 unsigned long InterlockedExchange (unsigned long * oldval,
00087                                                  unsigned long newval)
00088 {
00089 #if defined(sparc)
00090   asm volatile ("swap [%1],%0"
00091                 :"=r" (newval)
00092                 :"r" (oldval), "0" (newval)
00093                 : "memory");
00094 
00095 #endif
00096 #if defined(i386)
00097   asm volatile ("xchgl %0, %1"
00098                 : "=r" (newval)
00099                 : "m" (*oldval), "0" (newval)
00100                 : "memory");
00101 #endif
00102 #if defined(__sgi)
00103   newval = test_and_set (oldval, newval);
00104 #endif
00105 #if defined(ppc)
00106   int ret;
00107   asm volatile ("sync;"
00108                 "0:    lwarx %0,0,%1 ;"
00109                 "      xor. %0,%3,%0;"
00110                 "      bne 1f;"
00111                 "      stwcx. %2,0,%1;"
00112                 "      bne- 0b;"
00113                 "1:    sync"
00114         : "=&r"(ret)
00115         : "r"(oldval), "r"(newval), "r"(*oldval)
00116         : "cr0", "memory");
00117 #endif
00118 #if !(defined(sparc) || defined(i386) || defined(__sgi) || defined(ppc))
00119 #error "Hoard does not include support for user-level locks for this platform."
00120 #endif
00121   return newval;
00122 }
00123 #endif
00124 
00125 unsigned long hoardInterlockedExchange (unsigned long * oldval,
00126                                         unsigned long newval)
00127 {
00128   return InterlockedExchange (oldval, newval);
00129 }
00130 
00131 void hoardLockInit (hoardLockType& mutex) {
00132   InterlockedExchange (&mutex, UNLOCKED);
00133 }
00134 
00135 #include <stdio.h>
00136 
00137 void hoardLock (hoardLockType& mutex) {
00138   int spincount = 0;
00139   while (InterlockedExchange (&mutex, LOCKED) != UNLOCKED) {
00140     spincount++;
00141     if (spincount > 100) {
00142       hoardYield();
00143       spincount = 0;
00144     }
00145   }
00146 }
00147 
00148 void hoardUnlock (hoardLockType& mutex) {
00149         mutex = UNLOCKED;
00150 //  InterlockedExchange (&mutex, UNLOCKED);
00151 }
00152 
00153 #else
00154 
00155 // use non-user-level locks. 
00156 
00157 #endif // USER_LOCKS
00158 
00159 
00160 void hoardYield (void)
00161 {
00162   sched_yield();
00163 }
00164 
00165 
00166 extern "C" void *malloc (size_t);
00167 extern "C" void free (void *);
00168 
00169 
00170 #if USER_LOCKS
00171 static hoardLockType getMemoryLock = 0;
00172 #else
00173 static hoardLockType getMemoryLock = PTHREAD_MUTEX_INITIALIZER;
00174 #endif
00175 
00176 #include <stdio.h>
00177 
00178 void * hoardGetMemory (long size) {
00179   hoardLock (getMemoryLock);
00180   void * ptr = malloc (size);
00181   hoardUnlock (getMemoryLock);
00182   return ptr;
00183 }
00184 
00185 
00186 void hoardFreeMemory (void * ptr)
00187 {
00188   hoardLock (getMemoryLock);
00189   free (ptr);
00190   hoardUnlock (getMemoryLock);
00191 }
00192 
00193 
00194 int hoardGetPageSize (void)
00195 {
00196   return (int) sysconf(_SC_PAGESIZE);
00197 }
00198 
00199 
00200 #include <sys/types.h>
00201 #include <sys/stat.h>
00202 #include <fcntl.h>
00203 #include <string.h>
00204 
00205 
00206 int hoardGetNumProcessors (void)
00207 {
00208         static int numProcessors = 0;
00209 
00210         if (numProcessors == 0) {
00211                 // Ugly workaround.  Linux's sysconf indirectly calls malloc() (at
00212                 // least on multiprocessors).  So we just read the info from the
00213                 // proc file ourselves and count the occurrences of the word
00214                 // "processor".
00215                 
00216                 // We only parse the first 32K of the CPU file.  By my estimates,
00217                 // that should be more than enough for at least 64 processors.
00218                 enum { MAX_PROCFILE_SIZE = 32768 };
00219                 char line[MAX_PROCFILE_SIZE];
00220                 int fd = open ("/proc/cpuinfo", O_RDONLY);
00221                 assert (fd);
00222                 read(fd, line, MAX_PROCFILE_SIZE);
00223                 char * str = line;
00224                 while (str) {
00225                         str = strstr(str, "processor");
00226                         if (str) {
00227                                 numProcessors++;
00228                                 str++;
00229                         }
00230                 }
00231                 close (fd);
00232                 //FIXME: Currently the uniprocessos control path is broken, so force 
00233                 //the multiprocessor one even in the case of a single processor
00234                 if (numProcessors == 1) {
00235                         numProcessors = 2;
00236                 }
00237                 assert (numProcessors > 0);
00238         }
00239         return numProcessors;
00240 }
00241 
00242 } /* extern "C" */

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