| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author Xiao-Feng Li, 2006/10/05 |
| */ |
| |
| #ifndef _GC_PLATFORM_H_ |
| #define _GC_PLATFORM_H_ |
| |
| #include "port_vmem.h" |
| #include "port_atomic.h" |
| #include "port_malloc.h" |
| #include "port_barriers.h" |
| |
| #include <assert.h> |
| |
| #if defined(__linux__) || defined(FREEBSD) |
| #include <ctype.h> |
| #endif |
| |
| #ifndef MAP_ANONYMOUS |
| #define MAP_ANONYMOUS MAP_ANON |
| #endif |
| |
| #include <apr_time.h> |
| #include <apr_atomic.h> |
| |
| #include <open/hythread_ext.h> |
| |
| extern char* large_page_hint; |
| |
| #ifndef _DEBUG |
| |
| //#define RELEASE_DEBUG |
| #ifdef RELEASE_DEBUG |
| #undef assert |
| #define assert(x) do{ if(!(x)) __asm{int 3}}while(0) |
| #endif |
| |
| #endif //_DEBUG |
| |
| #ifndef _IPF_ |
| #define PREFETCH_SUPPORTED |
| #endif |
| |
| #ifdef _WINDOWS_ |
| #define FORCE_INLINE __forceinline |
| |
| #ifdef PREFETCH_SUPPORTED |
| #include <xmmintrin.h> |
| #define prefetchnta(pref_addr) _mm_prefetch((char*)(pref_addr), _MM_HINT_NTA ) |
| #endif /*ALLOC_PREFETCH*/ |
| |
| #elif defined (__linux__) || defined (FREEBSD) |
| #define FORCE_INLINE inline __attribute__((always_inline)) |
| |
| #ifdef PREFETCH_SUPPORTED |
| #define prefetchnta(pref_addr) __asm__ ("prefetchnta (%0)"::"r"(pref_addr)) |
| #endif /*PREFETCH_SUPPORTED*/ |
| #else |
| #define FORCE_INLINE inline |
| #endif /* _WINDOWS_ */ |
| |
| #ifdef PREFETCH_SUPPORTED |
| #define PREFETCH prefetchnta |
| #else |
| #define PREFETCH(x) |
| #endif |
| |
| #ifdef PREFETCH_SUPPORTED |
| extern Boolean mark_prefetch; |
| #endif |
| |
| #define ABS_DIFF(x, y) (((x)>(y))?((x)-(y)):((y)-(x))) |
| #define USEC_PER_SEC INT64_C(1000000) |
| |
| #define VmThreadHandle void* |
| #define VmEventHandle hysem_t |
| #define THREAD_OK TM_ERROR_NONE |
| #define THREAD_GROUP hythread_group_t |
| |
| extern THREAD_GROUP gc_thread_group; |
| |
| inline THREAD_GROUP get_gc_thread_group () { |
| if (!gc_thread_group) { |
| IDATA UNUSED stat = hythread_group_create(&gc_thread_group); |
| assert(stat == TM_ERROR_NONE); |
| } |
| return gc_thread_group; |
| } |
| |
| |
| inline int vm_wait_event(VmEventHandle event) |
| { int stat = (int)hysem_wait(event); |
| assert(stat == THREAD_OK); return stat; |
| } |
| |
| inline int vm_set_event(VmEventHandle event) |
| { int stat = (int)hysem_post(event); |
| assert(stat == THREAD_OK); return stat; |
| } |
| |
| inline int vm_reset_event(VmEventHandle event) |
| { int stat = (int)hysem_set(event,0); |
| assert(stat == THREAD_OK); return stat; |
| } |
| |
| inline int vm_create_event(VmEventHandle* event) |
| { return (int)hysem_create(event, 0, 1); } |
| |
| inline void vm_thread_yield() |
| { hythread_yield(); } |
| |
| inline void* vm_thread_local() |
| { return hythread_self(); } |
| |
| inline int vm_create_thread(int (*func)(void*), void *data) |
| { |
| hythread_t ret_thread = (hythread_t)STD_CALLOC(1,hythread_get_struct_size()); |
| assert(ret_thread); |
| |
| UDATA stacksize = 0; |
| UDATA priority = 5; |
| |
| return (int)hythread_create_ex(ret_thread, get_gc_thread_group(), stacksize, priority, NULL, |
| (hythread_entrypoint_t)func, data); |
| } |
| |
| inline int vm_thread_is_suspend_enable() |
| { |
| return (int)hythread_is_suspend_enabled(); |
| } |
| |
| inline int vm_suspend_all_threads() |
| { |
| int disable_count = hythread_reset_suspend_disable(); |
| hythread_suspend_all(NULL, NULL); |
| hythread_suspend_disable(); |
| return disable_count; |
| } |
| |
| inline int vm_suspend_all_threads( hythread_iterator_t *thread_iterator ) |
| { |
| int disable_count = hythread_reset_suspend_disable(); |
| hythread_suspend_all(thread_iterator, NULL); |
| hythread_suspend_disable(); |
| return disable_count; |
| } |
| inline void vm_resume_all_threads(int disable_count) |
| { |
| hythread_suspend_enable(); |
| hythread_resume_all(NULL); |
| hythread_set_suspend_disable(disable_count); |
| } |
| |
| inline void *atomic_casptr(volatile void **mem, void *with, const void *cmp) |
| { return apr_atomic_casptr(mem, with, cmp); } |
| |
| inline POINTER_SIZE_INT atomic_casptrsz(volatile POINTER_SIZE_INT* mem, |
| POINTER_SIZE_INT swap, |
| POINTER_SIZE_INT cmp) |
| { |
| // we can't use apr_atomic_casptr, which can't work correctly in 64bit machine. |
| #ifdef POINTER64 |
| return port_atomic_cas64(mem, swap, cmp); |
| #else |
| return apr_atomic_cas32(mem, swap, cmp); |
| #endif |
| } |
| |
| inline U_32 atomic_cas32(volatile unsigned int *mem, |
| apr_uint32_t swap, |
| apr_uint32_t cmp) |
| { return (U_32)apr_atomic_cas32(mem, swap, cmp); } |
| |
| inline U_32 atomic_inc32(volatile unsigned int *mem) |
| { return (U_32)apr_atomic_inc32(mem); } |
| |
| inline U_32 atomic_dec32(volatile unsigned int *mem) |
| { return (U_32)apr_atomic_dec32(mem); } |
| |
| inline U_32 atomic_add32(volatile unsigned int *mem, unsigned int val) |
| { return (U_32)apr_atomic_add32(mem, val); } |
| |
| #ifndef _WINDOWS_ |
| #include <sys/mman.h> |
| #endif |
| |
| inline unsigned int vm_get_system_alloc_unit() |
| { |
| #ifdef _WINDOWS_ |
| SYSTEM_INFO si; |
| GetSystemInfo(&si); |
| return si.dwAllocationGranularity; |
| #else |
| return port_vmem_page_sizes()[0]; |
| #endif |
| } |
| |
| inline void *vm_map_mem(void* start, POINTER_SIZE_INT size) |
| { |
| void* address; |
| #ifdef _WINDOWS_ |
| address = VirtualAlloc(start, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); |
| #else |
| address = mmap(start, size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
| if(address == MAP_FAILED) address = NULL; |
| |
| #endif /* ifdef _WINDOWS_ else */ |
| |
| return address; |
| } |
| |
| inline Boolean vm_unmap_mem(void* start, POINTER_SIZE_INT size) |
| { |
| unsigned int result; |
| #ifdef _WINDOWS_ |
| result = VirtualFree(start, 0, MEM_RELEASE); |
| #else |
| result = munmap(start, size); |
| if(result == 0) result = TRUE; |
| else result = FALSE; |
| #endif /* ifdef _WINDOWS_ else */ |
| |
| assert(result); /* expect that memory was really released */ |
| return result; |
| } |
| |
| inline void *vm_alloc_mem(void* start, POINTER_SIZE_INT size) |
| { |
| void* address; |
| #ifdef _WINDOWS_ |
| address = VirtualAlloc(start, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); |
| #else |
| address = mmap(start, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
| if(address == MAP_FAILED) address = NULL; |
| |
| #endif /* ifdef _WINDOWS_ else */ |
| |
| return address; |
| } |
| |
| inline Boolean vm_free_mem(void* start, POINTER_SIZE_INT size) |
| { |
| return vm_unmap_mem(start, size); |
| } |
| |
| inline void *vm_reserve_mem(void* start, POINTER_SIZE_INT size) |
| { |
| void* address; |
| #ifdef _WINDOWS_ |
| address = VirtualAlloc(start, size, MEM_RESERVE, PAGE_READWRITE); |
| #else |
| if(start == 0) |
| address = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
| else |
| address = mmap(start, size, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
| |
| if(address == MAP_FAILED) address = NULL; |
| |
| #endif /* ifdef _WINDOWS_ else */ |
| |
| return address; |
| } |
| |
| inline Boolean vm_release_mem(void* start, POINTER_SIZE_INT size) |
| { |
| return vm_unmap_mem(start, size); |
| } |
| |
| inline void *vm_commit_mem(void* start, POINTER_SIZE_INT size) |
| { |
| void* address; |
| #ifdef _WINDOWS_ |
| address = VirtualAlloc(start, size, MEM_COMMIT, PAGE_READWRITE); |
| #else |
| int result = mprotect(start, size, PROT_READ|PROT_WRITE); |
| if(result == 0) address = start; |
| else address = NULL; |
| #endif /* ifdef _WINDOWS_ else */ |
| |
| return address; |
| } |
| |
| inline Boolean vm_decommit_mem(void* start, POINTER_SIZE_INT size) |
| { |
| unsigned int result; |
| #ifdef _WINDOWS_ |
| result = VirtualFree(start, size, MEM_DECOMMIT); |
| #else |
| result = mprotect(start, size, PROT_NONE); |
| if(result == 0) result = TRUE; |
| else result = FALSE; |
| |
| #endif /* ifdef _WINDOWS_ else */ |
| |
| return result; |
| } |
| |
| inline void mem_fence() |
| { |
| port_rw_barrier(); |
| } |
| |
| inline int64 time_now() |
| { return apr_time_now(); } |
| |
| inline void string_to_upper(char* s) |
| { |
| while(*s){ |
| *s = toupper(*s); |
| s++; |
| } |
| } |
| |
| #ifdef PLATFORM_POSIX |
| #define max(x, y) (((x)>(y))?(x):(y)) |
| #define min(x, y) (((x)<(y))?(x):(y)) |
| #endif |
| |
| typedef volatile unsigned int SpinLock; |
| |
| enum Lock_State{ |
| FREE_LOCK, |
| LOCKED |
| }; |
| |
| #define try_lock(x) (!atomic_cas32(&(x), LOCKED, FREE_LOCK)) |
| #define lock(x) while( !try_lock(x)){ while( x==LOCKED ){ vm_thread_yield();}} |
| #define unlock(x) do{ x = FREE_LOCK;}while(0) |
| |
| #endif //_GC_PLATFORM_H_ |