aix.c (7199B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "primpl.h" 7 8 #ifdef AIX_HAVE_ATOMIC_OP_H 9 # include <sys/atomic_op.h> 10 11 PRInt32 _AIX_AtomicSet(PRInt32* val, PRInt32 newval) { 12 PRIntn oldval; 13 boolean_t stored; 14 oldval = fetch_and_add((atomic_p)val, 0); 15 do { 16 stored = compare_and_swap((atomic_p)val, &oldval, newval); 17 } while (!stored); 18 return oldval; 19 } /* _AIX_AtomicSet */ 20 #endif /* AIX_HAVE_ATOMIC_OP_H */ 21 22 #if defined(AIX_TIMERS) 23 24 # include <sys/time.h> 25 26 static PRUint32 _aix_baseline_epoch; 27 28 static void _MD_AixIntervalInit(void) { 29 timebasestruct_t real_time; 30 read_real_time(&real_time, TIMEBASE_SZ); 31 (void)time_base_to_time(&real_time, TIMEBASE_SZ); 32 _aix_baseline_epoch = real_time.tb_high; 33 } /* _MD_AixIntervalInit */ 34 35 PRIntervalTime _MD_AixGetInterval(void) { 36 PRIntn rv; 37 PRUint64 temp; 38 timebasestruct_t real_time; 39 read_real_time(&real_time, TIMEBASE_SZ); 40 (void)time_base_to_time(&real_time, TIMEBASE_SZ); 41 /* tb_high is in seconds, tb_low in 10(-9)seconds */ 42 temp = 1000000000ULL * (PRUint64)(real_time.tb_high - _aix_baseline_epoch); 43 temp += (PRUint64)real_time.tb_low; /* everything's 10(-9) seconds */ 44 temp >>= 16; /* now it's something way different */ 45 return (PRIntervalTime)temp; 46 } /* _MD_AixGetInterval */ 47 48 PRIntervalTime _MD_AixIntervalPerSec(void) { 49 return 1000000000ULL >> 16; /* that's 15258, I think */ 50 } /* _MD_AixIntervalPerSec */ 51 52 #endif /* defined(AIX_TIMERS) */ 53 54 #if !defined(PTHREADS_USER) 55 56 # if defined(_PR_PTHREADS) 57 58 /* 59 * AIX 4.3 has sched_yield(). AIX 4.2 has pthread_yield(). 60 * So we look up the appropriate function pointer at run time. 61 */ 62 63 # include <dlfcn.h> 64 65 int (*_PT_aix_yield_fcn)() = NULL; 66 int _pr_aix_send_file_use_disabled = 0; 67 68 void _MD_EarlyInit(void) { 69 void* main_app_handle; 70 char* evp; 71 72 main_app_handle = dlopen(NULL, RTLD_NOW); 73 PR_ASSERT(NULL != main_app_handle); 74 75 _PT_aix_yield_fcn = (int (*)())dlsym(main_app_handle, "sched_yield"); 76 if (!_PT_aix_yield_fcn) { 77 _PT_aix_yield_fcn = (int (*)())dlsym(main_app_handle, "pthread_yield"); 78 PR_ASSERT(NULL != _PT_aix_yield_fcn); 79 } 80 dlclose(main_app_handle); 81 82 if (evp = getenv("NSPR_AIX_SEND_FILE_USE_DISABLED")) { 83 if (1 == atoi(evp)) { 84 _pr_aix_send_file_use_disabled = 1; 85 } 86 } 87 88 # if defined(AIX_TIMERS) 89 _MD_AixIntervalInit(); 90 # endif 91 } 92 93 # else /* _PR_PTHREADS */ 94 95 void _MD_EarlyInit(void) { 96 # if defined(AIX_TIMERS) 97 _MD_AixIntervalInit(); 98 # endif 99 } 100 101 # endif /* _PR_PTHREADS */ 102 103 PRWord* _MD_HomeGCRegisters(PRThread* t, int isCurrent, int* np) { 104 # ifndef _PR_PTHREADS 105 if (isCurrent) { 106 (void)setjmp(CONTEXT(t)); 107 } 108 *np = sizeof(CONTEXT(t)) / sizeof(PRWord); 109 return (PRWord*)CONTEXT(t); 110 # else 111 *np = 0; 112 return NULL; 113 # endif 114 } 115 116 # ifndef _PR_PTHREADS 117 PR_IMPLEMENT(void) 118 _MD_SET_PRIORITY(_MDThread* thread, PRUintn newPri) { return; } 119 120 PR_IMPLEMENT(PRStatus) 121 _MD_InitializeThread(PRThread* thread) { return PR_SUCCESS; } 122 123 PR_IMPLEMENT(PRStatus) 124 _MD_WAIT(PRThread* thread, PRIntervalTime ticks) { 125 PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); 126 _PR_MD_SWITCH_CONTEXT(thread); 127 return PR_SUCCESS; 128 } 129 130 PR_IMPLEMENT(PRStatus) 131 _MD_WAKEUP_WAITER(PRThread* thread) { 132 if (thread) { 133 PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); 134 } 135 return PR_SUCCESS; 136 } 137 138 /* These functions should not be called for AIX */ 139 PR_IMPLEMENT(void) 140 _MD_YIELD(void) { PR_NOT_REACHED("_MD_YIELD should not be called for AIX."); } 141 142 PR_IMPLEMENT(PRStatus) 143 _MD_CREATE_THREAD(PRThread* thread, void (*start)(void*), 144 PRThreadPriority priority, PRThreadScope scope, 145 PRThreadState state, PRUint32 stackSize) { 146 PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for AIX."); 147 } 148 # endif /* _PR_PTHREADS */ 149 #endif /* PTHREADS_USER */ 150 151 /* 152 * NSPR 2.0 overrides the system select() and poll() functions. 153 * On AIX 4.2, we use dlopen("/unix", RTLD_NOW) and dlsym() to get 154 * at the original system select() and poll() functions. 155 */ 156 157 #if !defined(AIX_RENAME_SELECT) 158 159 # include <sys/select.h> 160 # include <sys/poll.h> 161 # include <dlfcn.h> 162 163 static int (*aix_select_fcn)() = NULL; 164 static int (*aix_poll_fcn)() = NULL; 165 166 int _MD_SELECT(int width, fd_set* r, fd_set* w, fd_set* e, struct timeval* t) { 167 int rv; 168 169 if (!aix_select_fcn) { 170 void* aix_handle; 171 172 aix_handle = dlopen("/unix", RTLD_NOW); 173 if (!aix_handle) { 174 PR_SetError(PR_UNKNOWN_ERROR, 0); 175 return -1; 176 } 177 aix_select_fcn = (int (*)())dlsym(aix_handle, "select"); 178 dlclose(aix_handle); 179 if (!aix_select_fcn) { 180 PR_SetError(PR_UNKNOWN_ERROR, 0); 181 return -1; 182 } 183 } 184 rv = (*aix_select_fcn)(width, r, w, e, t); 185 return rv; 186 } 187 188 int _MD_POLL(void* listptr, unsigned long nfds, long timeout) { 189 int rv; 190 191 if (!aix_poll_fcn) { 192 void* aix_handle; 193 194 aix_handle = dlopen("/unix", RTLD_NOW); 195 if (!aix_handle) { 196 PR_SetError(PR_UNKNOWN_ERROR, 0); 197 return -1; 198 } 199 aix_poll_fcn = (int (*)())dlsym(aix_handle, "poll"); 200 dlclose(aix_handle); 201 if (!aix_poll_fcn) { 202 PR_SetError(PR_UNKNOWN_ERROR, 0); 203 return -1; 204 } 205 } 206 rv = (*aix_poll_fcn)(listptr, nfds, timeout); 207 return rv; 208 } 209 210 #else 211 212 /* 213 * In AIX versions prior to 4.2, we use the two-step rename/link trick. 214 * The binary must contain at least one "poll" symbol for linker's rename 215 * to work. So we must have this dummy function that references poll(). 216 */ 217 # include <sys/poll.h> 218 void _pr_aix_dummy() { poll(0, 0, 0); } 219 220 #endif /* !defined(AIX_RENAME_SELECT) */ 221 222 #ifdef _PR_HAVE_ATOMIC_CAS 223 224 # include "pratom.h" 225 226 # define _PR_AIX_ATOMIC_LOCK -1 227 228 PR_IMPLEMENT(void) 229 PR_StackPush(PRStack* stack, PRStackElem* stack_elem) { 230 PRStackElem* addr; 231 boolean_t locked = TRUE; 232 233 /* Is it safe to cast a pointer to an int? */ 234 PR_ASSERT(sizeof(int) == sizeof(PRStackElem*)); 235 do { 236 while ((addr = stack->prstk_head.prstk_elem_next) == 237 (PRStackElem*)_PR_AIX_ATOMIC_LOCK); 238 locked = _check_lock((atomic_p)&stack->prstk_head.prstk_elem_next, 239 (int)addr, _PR_AIX_ATOMIC_LOCK); 240 } while (locked == TRUE); 241 stack_elem->prstk_elem_next = addr; 242 _clear_lock((atomic_p)&stack->prstk_head.prstk_elem_next, (int)stack_elem); 243 return; 244 } 245 246 PR_IMPLEMENT(PRStackElem*) 247 PR_StackPop(PRStack* stack) { 248 PRStackElem* element; 249 boolean_t locked = TRUE; 250 251 /* Is it safe to cast a pointer to an int? */ 252 PR_ASSERT(sizeof(int) == sizeof(PRStackElem*)); 253 do { 254 while ((element = stack->prstk_head.prstk_elem_next) == 255 (PRStackElem*)_PR_AIX_ATOMIC_LOCK); 256 locked = _check_lock((atomic_p)&stack->prstk_head.prstk_elem_next, 257 (int)element, _PR_AIX_ATOMIC_LOCK); 258 } while (locked == TRUE); 259 260 if (element == NULL) { 261 _clear_lock((atomic_p)&stack->prstk_head.prstk_elem_next, NULL); 262 } else { 263 _clear_lock((atomic_p)&stack->prstk_head.prstk_elem_next, 264 (int)element->prstk_elem_next); 265 } 266 return element; 267 } 268 269 #endif /* _PR_HAVE_ATOMIC_CAS */