⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arch-specific.cpp

📁 newos is new operation system
💻 CPP
字号:
///-*-C++-*-////////////////////////////////////////////////////////////////////// Hoard: A Fast, Scalable, and Memory-Efficient Allocator//        for Shared-Memory Multiprocessors// Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery//// Copyright (c) 1998-2000, The University of Texas at Austin.//// This library is free software; you can redistribute it and/or modify// it under the terms of the GNU Library General Public License as// published by the Free Software Foundation, http://www.fsf.org.//// This library is distributed in the hope that it will be useful, but// WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU// Library General Public License for more details.//////////////////////////////////////////////////////////////////////////////////#include <assert.h>#include "arch-specific.h"// How many iterations we spin waiting for a lock.enum { SPIN_LIMIT = 100 };// The values of a user-level lock.enum { UNLOCKED = 0, LOCKED = 1 };extern "C" {#ifdef NEWOS#include <stdio.h>#include <sys/syscalls.h>#include <sys/atomic.h>int hoardGetThreadID (void){  return _kern_get_current_thread_id();}void hoardLockInit (hoardLockType &lock){ 	lock.ben = 0;	lock.sem = _kern_sem_create(1, "a hoard lock");}void hoardLock (hoardLockType &lock){  if((atomic_add(&(lock.ben), 1)) >= 1) _kern_sem_acquire(lock.sem, 1);}void hoardUnlock (hoardLockType &lock){  if((atomic_add(&(lock.ben), -1)) > 1) _kern_sem_release(lock.sem, 1);}int hoardGetPageSize (void){  return 4096;}int hoardGetNumProcessors (void){  // XXX return the real number of procs here  return 1;}static region_id heap_region = -1;static addr_t brk;int __heap_init(){	// XXX do something better here	if(heap_region < 0) {		heap_region = _kern_vm_create_anonymous_region("heap", (void **)&brk,			REGION_ADDR_ANY_ADDRESS, 4*1024*1024, REGION_WIRING_LAZY, LOCK_RW);	}	return 0;}class heap_init_hack_t{public:	heap_init_hack_t(void) {		__heap_init();	}} heap_init_hack;void * hoardSbrk (long size){	void *ret = (void *)brk;	brk += size;	return ret;}void hoardUnsbrk (void * ptr, long size){  // NOT CURRENTLY IMPLEMENTED!}void hoardYield (void){}#elif defined(WIN32)unsigned long hoardInterlockedExchange (unsigned long * oldval,					unsigned long newval){  return InterlockedExchange (reinterpret_cast<long *>(oldval), newval);}void hoardCreateThread (hoardThreadType& t,			void *(*function) (void *),			void * arg){  t = CreateThread (0, 0, (LPTHREAD_START_ROUTINE) function, (LPVOID) arg, 0, 0);}void hoardJoinThread (hoardThreadType& t){  WaitForSingleObject (t, INFINITE);}void hoardSetConcurrency (int){}int hoardGetThreadID (void) {  // Threads from Windows 2000 are 4 apart,  // so we shift them over to get an appropriate thread id.  int tid = GetCurrentThreadId() >> 2;  return tid;}void hoardLockInit (hoardLockType& mutex) {  InterlockedExchange (&mutex, 0);}void hoardLock (hoardLockType& mutex) {  // A yielding lock (with an initial spin).  int i;  while (1) {    i = 0;    while (i < SPIN_LIMIT) {		if (mutex != LOCKED)	     if (InterlockedExchange (&mutex, LOCKED) == UNLOCKED) {			// We got the lock.			return;      }      i++;    }    // Yield to other threads.    Sleep (0);  }}void hoardYield (void) {  Sleep (0);}void hoardUnlock (hoardLockType& mutex) {  InterlockedExchange (&mutex, UNLOCKED);}void * hoardSbrk (long size){  void * ptr = HeapAlloc (GetProcessHeap(), 0, size);  return (void *) ptr;}void hoardUnsbrk (void * ptr, long size){	HeapFree (GetProcessHeap(), 0, ptr);}int hoardGetPageSize (void){  SYSTEM_INFO infoReturn[1];  GetSystemInfo (infoReturn);  return (int) (infoReturn -> dwPageSize);}int hoardGetNumProcessors (void){  static int numProcessors = 0;  if (numProcessors == 0) {    SYSTEM_INFO infoReturn[1];    GetSystemInfo (infoReturn);    numProcessors = (int) (infoReturn -> dwNumberOfProcessors);  }  return numProcessors;}#elif defined(__BEOS__)#include <OS.h>#include <unistd.h>void hoardCreateThread (hoardThreadType &t,			void *( *function)( void *),			void *arg){  t = spawn_thread((int32 (*)(void*))function, "some thread",		   B_NORMAL_PRIORITY, arg);  if (t >= B_OK) resume_thread(t);  else debugger("spawn_thread() failed!");}void hoardJoinThread (hoardThreadType &t){  status_t dummy;  wait_for_thread(t, &dummy);}void hoardSetConcurrency (int){}int hoardGetThreadID (void){  return find_thread(0);}void hoardLockInit (hoardLockType &lock){  lock.ben = 0;  lock.sem = create_sem(0, "a hoard lock");}void hoardLock (hoardLockType &lock){  if((atomic_add(&(lock.ben), 1)) >= 1) acquire_sem(lock.sem);}void hoardUnlock (hoardLockType &lock){  if((atomic_add(&(lock.ben), -1)) > 1) release_sem(lock.sem);}int hoardGetPageSize (void){  return B_PAGE_SIZE;}int hoardGetNumProcessors (void){  system_info si;  status_t result = get_system_info(&si);  assert (result == B_OK);  return si.cpu_count;}void * hoardSbrk (long size){  return sbrk(size + hoardHeap::ALIGNMENT - 1);}void hoardUnsbrk (void * ptr, long size){  // NOT CURRENTLY IMPLEMENTED!}void hoardYield (void){}unsigned long hoardInterlockedExchange (unsigned long * oldval,					unsigned long newval){  // This *should* be made atomic.  It's never used in the BeOS  // version, so this is included strictly for completeness.  unsigned long o = *oldval;  *oldval = newval;  return o;}#else // UNIX#if USE_SPROC#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <ulocks.h>#endifvoid hoardCreateThread (hoardThreadType& t,			void *(*function) (void *),			void * arg){#if USE_SPROC  typedef void (*sprocFunction) (void *);  t = sproc ((sprocFunction) function, PR_SADDR, arg);#else  pthread_attr_t attr;  pthread_attr_init (&attr);#if defined(_AIX)  // Bound (kernel-level) threads.  pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);#endif  pthread_create (&t, &attr, function, arg);#endif}void hoardJoinThread (hoardThreadType& t){#if USE_SPROC  waitpid (t, 0, 0);#else  pthread_join (t, NULL);#endif}#if defined(__linux)// This extern declaration is required for Linux.extern "C" void pthread_setconcurrency (int n);#endifvoid hoardSetConcurrency (int n){#if USE_SPROC  usconfig (CONF_INITUSERS, n);#elif defined(__SVR4) // Solaris  thr_setconcurrency (n);#else  pthread_setconcurrency (n);#endif}#if defined(__SVR4) // Solaris// Solaris's two-level threads model gives us an edge here;// we can hash on the LWP's id. This helps us in two ways:// (1) there are likely to be far fewer LWP's than threads,// (2) if there's a one-to-one correspondence between LWP's//     and the number of processors (usually the case), then//     the number of heaps used will be the same as the number//     of processors (the optimal case).// Here we rely on an undocumented call in libthread.so, which// turns out to be MUCH cheaper than the documented _lwp_self(). Go figure.extern "C" unsigned int lwp_self(void);#endifint hoardGetThreadID (void) {#if USE_SPROC  // This hairiness has the same effect as calling getpid(),  // but it's MUCH faster since it avoids making a system call  // and just accesses the sproc-local data directly.  int pid = (int) PRDA->sys_prda.prda_sys.t_pid;  return pid;#else#if defined(__linux)  // Consecutive thread id's in Linux are 1024 apart;  // dividing off the 1024 gives us an appropriate thread id.  return (int) pthread_self() >> 10; // (>> 10 = / 1024)#endif#if defined(__AIX)  // Consecutive thread id's in AIX are 257 apart;  // dividing off the 257 gives us an appropriate thread id.  return (int) pthread_self() / 257;#endif#if defined(__SVR4)  return (int) lwp_self();#endif  return (int) pthread_self();#endif}// If we are using either Intel or SPARC,// we use our own lock implementation// (spin then yield). This is much cheaper than// the ordinary mutex, at least on Linux and Solaris.#if USER_LOCKS && (defined(i386) || defined(sparc) || defined(__sgi) || defined(ppc))#include <sched.h>#if defined(__sgi)#include <mutex.h>#endif// Atomically://   retval = *oldval;//   *oldval = newval;//   return retval;#if defined(sparc) && !defined(__GNUC__)extern "C" unsigned long InterlockedExchange (unsigned long * oldval,					      unsigned long newval);#elseunsigned long InterlockedExchange (unsigned long * oldval,						 unsigned long newval){#if defined(sparc)  asm volatile ("swap [%1],%0"		:"=r" (newval)		:"r" (oldval), "0" (newval)		: "memory");#endif#if defined(i386)  asm volatile ("xchgl %0, %1"		: "=r" (newval)		: "m" (*oldval), "0" (newval)		: "memory");#endif#if defined(__sgi)  newval = test_and_set (oldval, newval);#endif#if defined(ppc)  int ret;  asm volatile ("sync;"		"0:    lwarx %0,0,%1 ;"		"      xor. %0,%3,%0;"		"      bne 1f;"		"      stwcx. %2,0,%1;"		"      bne- 0b;"		"1:    sync"	: "=&r"(ret)	: "r"(oldval), "r"(newval), "r"(*oldval)	: "cr0", "memory");#endif  return newval;}#endifunsigned long hoardInterlockedExchange (unsigned long * oldval,					unsigned long newval){  return InterlockedExchange (oldval, newval);}void hoardLockInit (hoardLockType& mutex) {  InterlockedExchange (&mutex, UNLOCKED);}#include <stdio.h>void hoardLock (hoardLockType& mutex) {  // A yielding lock (with an initial spin).  int i;  while (1) {    i = 0;    while (i < SPIN_LIMIT) {      if (InterlockedExchange (&mutex, LOCKED) == UNLOCKED) {	// We got the lock.	return;      }      i++;    }    // The lock is still being held by someone else.    // Give up our quantum.    sched_yield ();  }}void hoardUnlock (hoardLockType& mutex) {  InterlockedExchange (&mutex, UNLOCKED);}#else// use non-user-level locks.#endif // USER_LOCKSvoid hoardYield (void){  sched_yield ();}#if 1 // !(defined(__sgi))#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/mman.h>#endifvoid * hoardSbrk (long size) {  // Use mmap for everything but SGI.  // Apparently sproc's and mmap's don't cooperate.#if 0 // defined(__sgi)  // Protect calls to sbrk() with a lock.#if USER_LOCKS  static hoardLockType sbrkLock = 0;#else  static hoardLockType sbrkLock = PTHREAD_MUTEX_INITIALIZER;#endif  hoardLock (sbrkLock);  // The "sizeof(double)" should equal hoardHeap::ALIGNMENT.  // This is a workaround (compiler error in g++).  void * moreMemory = sbrk (size + sizeof(double) - 1);  hoardUnlock (sbrkLock);  return moreMemory;#else#if defined(linux)#if USER_LOCKS  static hoardLockType sbrkLock = 0;#else  static hoardLockType sbrkLock = PTHREAD_MUTEX_INITIALIZER;#endif#endif  // Use mmap to get memory from the backing store.  static int fd = ::open ("/dev/zero", O_RDWR);#if defined(linux)  hoardLock (sbrkLock);  // Map starting at this address to maximize the amount of memory  // available to Hoard. Thanks to Jim Nance for this tip.  char * ptr = (char *) mmap ((void *) 0x10000000, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);#else  char * ptr = (char *) mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);#endif  char * retPtr;  if (ptr == (char *) MAP_FAILED) {    retPtr = NULL;  } else {    retPtr = ptr;  }#if defined(linux)  hoardUnlock (sbrkLock);#endif  return retPtr;#endif}void hoardUnsbrk (void * ptr, long size){#if defined(linux)#if USER_LOCKS  static hoardLockType sbrkLock = 0;#else  static hoardLockType sbrkLock = PTHREAD_MUTEX_INITIALIZER;#endif#endif#if defined(linux)  hoardLock (sbrkLock);#endif  int result = munmap ((char *) ptr, size);  assert (result == 0);#if defined(linux)  hoardUnlock (sbrkLock);#endif}int hoardGetPageSize (void){  return (int) sysconf(_SC_PAGESIZE);}#if defined(linux)#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#endif#if defined(__sgi)#include <sys/types.h>#include <sys/sysmp.h>#include <sys/sysinfo.h>#endifint hoardGetNumProcessors (void){#if !(defined(linux))#if defined(__sgi)  static int np = (int) sysmp(MP_NAPROCS);  return np;#else  static int np = (int) sysconf(_SC_NPROCESSORS_ONLN);  return np;#endif#else  static int numProcessors = 0;  if (numProcessors == 0) {    // Ugly workaround.  Linux's sysconf indirectly calls malloc() (at    // least on multiprocessors).  So we just read the info from the    // proc file ourselves and count the occurrences of the word    // "processor".    // We only parse the first 32K of the CPU file.  By my estimates,    // that should be more than enough for at least 64 processors.    enum { MAX_PROCFILE_SIZE = 32768 };    char line[MAX_PROCFILE_SIZE];    int fd = open ("/proc/cpuinfo", O_RDONLY);    assert (fd);    read(fd, line, MAX_PROCFILE_SIZE);    char * str = line;    while (str) {      str = strstr(str, "processor");      if (str) {	numProcessors++;	str++;      }    }    close (fd);    assert (numProcessors > 0);  }  return numProcessors;#endif}#endif // UNIX}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -