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 #ifndef nspr_solaris_defs_h___ 7 #define nspr_solaris_defs_h___ 8 9 /* 10 * Internal configuration macros 11 */ 12 13 #define PR_LINKER_ARCH "solaris" 14 #define _PR_SI_SYSNAME "SOLARIS" 15 #ifdef sparc 16 #define _PR_SI_ARCHITECTURE "sparc" 17 #elif defined(__x86_64) 18 #define _PR_SI_ARCHITECTURE "x86-64" 19 #elif defined(i386) 20 #define _PR_SI_ARCHITECTURE "x86" 21 #else 22 #error unknown processor 23 #endif 24 #define PR_DLL_SUFFIX ".so" 25 26 #define _PR_VMBASE 0x30000000 27 #define _PR_STACK_VMBASE 0x50000000 28 #define _MD_DEFAULT_STACK_SIZE (2*65536L) 29 #define _MD_MMAP_FLAGS MAP_SHARED 30 31 #undef HAVE_STACK_GROWING_UP 32 33 #ifndef HAVE_WEAK_IO_SYMBOLS 34 #define HAVE_WEAK_IO_SYMBOLS 35 #endif 36 37 #undef HAVE_WEAK_MALLOC_SYMBOLS 38 #define HAVE_DLL 39 #define USE_DLFCN 40 #define NEED_STRFTIME_LOCK 41 42 /* 43 * Intel x86 has atomic instructions. 44 * 45 * Sparc v8 does not have instructions to efficiently implement 46 * atomic increment/decrement operations. We use the default 47 * atomic routine implementation in pratom.c. 48 * 49 * 64-bit Solaris requires sparc v9, which has atomic instructions. 50 */ 51 #if defined(i386) || defined(IS_64) 52 #define _PR_HAVE_ATOMIC_OPS 53 #endif 54 55 #define _PR_POLL_AVAILABLE 56 #define _PR_USE_POLL 57 #define _PR_STAT_HAS_ST_ATIM 58 #ifdef SOLARIS2_5 59 #define _PR_HAVE_SYSV_SEMAPHORES 60 #define PR_HAVE_SYSV_NAMED_SHARED_MEMORY 61 #else 62 #define _PR_HAVE_POSIX_SEMAPHORES 63 #define PR_HAVE_POSIX_NAMED_SHARED_MEMORY 64 #endif 65 #define _PR_HAVE_GETIPNODEBYNAME 66 #define _PR_HAVE_GETIPNODEBYADDR 67 #define _PR_HAVE_GETADDRINFO 68 #define _PR_INET6_PROBE 69 #define _PR_ACCEPT_INHERIT_NONBLOCK 70 #ifdef _PR_INET6 71 #define _PR_HAVE_INET_NTOP 72 #else 73 #define AF_INET6 26 74 struct addrinfo { 75 int ai_flags; 76 int ai_family; 77 int ai_socktype; 78 int ai_protocol; 79 size_t ai_addrlen; 80 char *ai_canonname; 81 struct sockaddr *ai_addr; 82 struct addrinfo *ai_next; 83 }; 84 #define AI_CANONNAME 0x0010 85 #define AI_V4MAPPED 0x0001 86 #define AI_ALL 0x0002 87 #define AI_ADDRCONFIG 0x0004 88 #define _PR_HAVE_MD_SOCKADDR_IN6 89 /* isomorphic to struct in6_addr on Solaris 8 */ 90 struct _md_in6_addr { 91 union { 92 PRUint8 _S6_u8[16]; 93 PRUint32 _S6_u32[4]; 94 PRUint32 __S6_align; 95 } _S6_un; 96 }; 97 /* isomorphic to struct sockaddr_in6 on Solaris 8 */ 98 struct _md_sockaddr_in6 { 99 PRUint16 sin6_family; 100 PRUint16 sin6_port; 101 PRUint32 sin6_flowinfo; 102 struct _md_in6_addr sin6_addr; 103 PRUint32 sin6_scope_id; 104 PRUint32 __sin6_src_id; 105 }; 106 #endif 107 #if defined(_PR_PTHREADS) 108 #define _PR_HAVE_GETHOST_R 109 #define _PR_HAVE_GETHOST_R_POINTER 110 #endif 111 112 #include "prinrval.h" 113 #define _MD_INTERVAL_INIT() 114 NSPR_API(PRIntervalTime) _MD_Solaris_GetInterval(void); 115 #define _MD_GET_INTERVAL _MD_Solaris_GetInterval 116 NSPR_API(PRIntervalTime) _MD_Solaris_TicksPerSecond(void); 117 #define _MD_INTERVAL_PER_SEC _MD_Solaris_TicksPerSecond 118 119 #if defined(_PR_HAVE_ATOMIC_OPS) 120 /* 121 ** Atomic Operations 122 */ 123 #define _MD_INIT_ATOMIC() 124 125 NSPR_API(PRInt32) _MD_AtomicIncrement(PRInt32 *val); 126 #define _MD_ATOMIC_INCREMENT _MD_AtomicIncrement 127 128 NSPR_API(PRInt32) _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val); 129 #define _MD_ATOMIC_ADD _MD_AtomicAdd 130 131 NSPR_API(PRInt32) _MD_AtomicDecrement(PRInt32 *val); 132 #define _MD_ATOMIC_DECREMENT _MD_AtomicDecrement 133 134 NSPR_API(PRInt32) _MD_AtomicSet(PRInt32 *val, PRInt32 newval); 135 #define _MD_ATOMIC_SET _MD_AtomicSet 136 #endif /* _PR_HAVE_ATOMIC_OPS */ 137 138 #if defined(_PR_PTHREADS) 139 140 NSPR_API(void) _MD_EarlyInit(void); 141 142 #define _MD_EARLY_INIT _MD_EarlyInit 143 #define _MD_FINAL_INIT _PR_UnixInit 144 145 #else /* _PR_PTHREADS */ 146 147 /* 148 * _PR_LOCAL_THREADS_ONLY implementation on Solaris 149 */ 150 151 #include "prthread.h" 152 153 #include <errno.h> 154 #include <ucontext.h> 155 #include <sys/stack.h> 156 #include <synch.h> 157 158 /* 159 ** Initialization Related definitions 160 */ 161 162 NSPR_API(void) _MD_EarlyInit(void); 163 NSPR_API(void) _MD_SolarisInit(); 164 #define _MD_EARLY_INIT _MD_EarlyInit 165 #define _MD_FINAL_INIT _MD_SolarisInit 166 #define _MD_INIT_THREAD _MD_InitializeThread 167 168 #ifdef USE_SETJMP 169 170 #include <setjmp.h> 171 172 #define _PR_CONTEXT_TYPE jmp_buf 173 174 #ifdef sparc 175 #define _MD_GET_SP(_t) (_t)->md.context[2] 176 #else 177 #define _MD_GET_SP(_t) (_t)->md.context[4] 178 #endif 179 180 #define PR_NUM_GCREGS _JBLEN 181 #define CONTEXT(_thread) (_thread)->md.context 182 183 #else /* ! USE_SETJMP */ 184 185 #ifdef sparc 186 #define _PR_CONTEXT_TYPE ucontext_t 187 #define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[REG_SP] 188 /* 189 ** Sparc's use register windows. the _MD_GetRegisters for the sparc's 190 ** doesn't actually store anything into the argument buffer; instead the 191 ** register windows are homed to the stack. I assume that the stack 192 ** always has room for the registers to spill to... 193 */ 194 #define PR_NUM_GCREGS 0 195 #else 196 #define _PR_CONTEXT_TYPE unsigned int edi; sigset_t oldMask, blockMask; ucontext_t 197 #define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[USP] 198 #define PR_NUM_GCREGS _JBLEN 199 #endif 200 201 #define CONTEXT(_thread) (&(_thread)->md.context) 202 203 #endif /* ! USE_SETJMP */ 204 205 #include <time.h> 206 /* 207 * Because clock_gettime() on Solaris/x86 always generates a 208 * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(), 209 * which is implemented using gettimeofday(). 210 */ 211 #ifdef i386 212 #define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt)) 213 #else 214 #define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt)) 215 #endif /* i386 */ 216 217 #define _MD_SAVE_ERRNO(_thread) (_thread)->md.errcode = errno; 218 #define _MD_RESTORE_ERRNO(_thread) errno = (_thread)->md.errcode; 219 220 #ifdef sparc 221 222 #ifdef USE_SETJMP 223 #define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ 224 PR_BEGIN_MACRO \ 225 int *context = (_thread)->md.context; \ 226 *status = PR_TRUE; \ 227 (void) setjmp(context); \ 228 (_thread)->md.context[1] = (int) ((_sp) - 64); \ 229 (_thread)->md.context[2] = (int) _main; \ 230 (_thread)->md.context[3] = (int) _main + 4; \ 231 _thread->no_sched = 0; \ 232 PR_END_MACRO 233 234 #define _MD_SWITCH_CONTEXT(_thread) \ 235 if (!setjmp(CONTEXT(_thread))) { \ 236 _MD_SAVE_ERRNO(_thread) \ 237 _MD_SET_LAST_THREAD(_thread); \ 238 _MD_SET_CURRENT_THREAD(_thread); \ 239 _PR_Schedule(); \ 240 } 241 242 #define _MD_RESTORE_CONTEXT(_newThread) \ 243 { \ 244 _MD_RESTORE_ERRNO(_newThread) \ 245 _MD_SET_CURRENT_THREAD(_newThread); \ 246 longjmp(CONTEXT(_newThread), 1); \ 247 } 248 249 #else 250 /* 251 ** Initialize the thread context preparing it to execute _main. 252 */ 253 #define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ 254 PR_BEGIN_MACRO \ 255 ucontext_t *uc = CONTEXT(_thread); \ 256 *status = PR_TRUE; \ 257 getcontext(uc); \ 258 uc->uc_stack.ss_sp = (char *) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8); \ 259 uc->uc_stack.ss_size = _thread->stack->stackSize; \ 260 uc->uc_stack.ss_flags = 0; /* ? */ \ 261 uc->uc_mcontext.gregs[REG_SP] = (unsigned int) uc->uc_stack.ss_sp; \ 262 uc->uc_mcontext.gregs[REG_PC] = (unsigned int) _main; \ 263 uc->uc_mcontext.gregs[REG_nPC] = (unsigned int) ((char*)_main)+4; \ 264 uc->uc_flags = UC_ALL; \ 265 _thread->no_sched = 0; \ 266 PR_END_MACRO 267 268 /* 269 ** Switch away from the current thread context by saving its state and 270 ** calling the thread scheduler. Reload cpu when we come back from the 271 ** context switch because it might have changed. 272 */ 273 #define _MD_SWITCH_CONTEXT(_thread) \ 274 PR_BEGIN_MACRO \ 275 if (!getcontext(CONTEXT(_thread))) { \ 276 _MD_SAVE_ERRNO(_thread); \ 277 _MD_SET_LAST_THREAD(_thread); \ 278 _PR_Schedule(); \ 279 } \ 280 PR_END_MACRO 281 282 /* 283 ** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or 284 ** initialized by _MD_INIT_CONTEXT. 285 */ 286 #define _MD_RESTORE_CONTEXT(_newThread) \ 287 PR_BEGIN_MACRO \ 288 ucontext_t *uc = CONTEXT(_newThread); \ 289 uc->uc_mcontext.gregs[11] = 1; \ 290 _MD_RESTORE_ERRNO(_newThread); \ 291 _MD_SET_CURRENT_THREAD(_newThread); \ 292 setcontext(uc); \ 293 PR_END_MACRO 294 #endif 295 296 #else /* x86 solaris */ 297 298 #ifdef USE_SETJMP 299 300 #define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ 301 PR_BEGIN_MACRO \ 302 *status = PR_TRUE; \ 303 if (setjmp(CONTEXT(_thread))) _main(); \ 304 _MD_GET_SP(_thread) = (int) ((_sp) - 64); \ 305 PR_END_MACRO 306 307 #define _MD_SWITCH_CONTEXT(_thread) \ 308 if (!setjmp(CONTEXT(_thread))) { \ 309 _MD_SAVE_ERRNO(_thread) \ 310 _PR_Schedule(); \ 311 } 312 313 #define _MD_RESTORE_CONTEXT(_newThread) \ 314 { \ 315 _MD_RESTORE_ERRNO(_newThread) \ 316 _MD_SET_CURRENT_THREAD(_newThread); \ 317 longjmp(CONTEXT(_newThread), 1); \ 318 } 319 320 #else /* USE_SETJMP */ 321 322 #define WINDOWSIZE 0 323 324 int getedi(void); 325 void setedi(int); 326 327 #define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ 328 PR_BEGIN_MACRO \ 329 ucontext_t *uc = CONTEXT(_thread); \ 330 *status = PR_TRUE; \ 331 getcontext(uc); \ 332 /* Force sp to be double aligned! */ \ 333 uc->uc_mcontext.gregs[USP] = (int) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8); \ 334 uc->uc_mcontext.gregs[PC] = (int) _main; \ 335 (_thread)->no_sched = 0; \ 336 PR_END_MACRO 337 338 /* getcontext() may return 1, contrary to what the man page says */ 339 #define _MD_SWITCH_CONTEXT(_thread) \ 340 PR_BEGIN_MACRO \ 341 ucontext_t *uc = CONTEXT(_thread); \ 342 PR_ASSERT(_thread->no_sched); \ 343 sigfillset(&((_thread)->md.blockMask)); \ 344 sigprocmask(SIG_BLOCK, &((_thread)->md.blockMask), \ 345 &((_thread)->md.oldMask)); \ 346 (_thread)->md.edi = getedi(); \ 347 if (! getcontext(uc)) { \ 348 sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \ 349 uc->uc_mcontext.gregs[EDI] = (_thread)->md.edi; \ 350 _MD_SAVE_ERRNO(_thread) \ 351 _MD_SET_LAST_THREAD(_thread); \ 352 _PR_Schedule(); \ 353 } else { \ 354 sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \ 355 setedi((_thread)->md.edi); \ 356 PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \ 357 _MD_LAST_THREAD()->no_sched = 0; \ 358 } \ 359 PR_END_MACRO 360 361 /* 362 ** Restore a thread context, saved by _PR_SWITCH_CONTEXT 363 */ 364 #define _MD_RESTORE_CONTEXT(_newthread) \ 365 PR_BEGIN_MACRO \ 366 ucontext_t *uc = CONTEXT(_newthread); \ 367 uc->uc_mcontext.gregs[EAX] = 1; \ 368 _MD_RESTORE_ERRNO(_newthread) \ 369 _MD_SET_CURRENT_THREAD(_newthread); \ 370 (_newthread)->no_sched = 1; \ 371 setcontext(uc); \ 372 PR_END_MACRO 373 #endif /* USE_SETJMP */ 374 375 #endif /* sparc */ 376 377 struct _MDLock { 378 PRInt8 notused; 379 }; 380 381 struct _MDCVar { 382 PRInt8 notused; 383 }; 384 385 struct _MDSemaphore { 386 PRInt8 notused; 387 }; 388 389 struct _MDThread { 390 _PR_CONTEXT_TYPE context; 391 int errcode; 392 int id; 393 }; 394 395 struct _MDThreadStack { 396 PRInt8 notused; 397 }; 398 399 struct _MDSegment { 400 PRInt8 notused; 401 }; 402 403 /* 404 * md-specific cpu structure field 405 */ 406 #define _PR_MD_MAX_OSFD FD_SETSIZE 407 408 struct _MDCPU_Unix { 409 PRCList ioQ; 410 PRUint32 ioq_timeout; 411 PRInt32 ioq_max_osfd; 412 PRInt32 ioq_osfd_cnt; 413 #ifndef _PR_USE_POLL 414 fd_set fd_read_set, fd_write_set, fd_exception_set; 415 PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], 416 fd_exception_cnt[_PR_MD_MAX_OSFD]; 417 #else 418 struct pollfd *ioq_pollfds; 419 int ioq_pollfds_size; 420 #endif /* _PR_USE_POLL */ 421 }; 422 423 #define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) 424 #define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) 425 #define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) 426 #define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) 427 #define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) 428 #define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) 429 #define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) 430 #define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) 431 #define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) 432 #define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) 433 #define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) 434 #define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) 435 #define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) 436 437 #define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 438 439 struct _MDCPU { 440 struct _MDCPU_Unix md_unix; 441 }; 442 443 #define _MD_INIT_LOCKS() 444 #define _MD_NEW_LOCK(lock) PR_SUCCESS 445 #define _MD_FREE_LOCK(lock) 446 #define _MD_LOCK(lock) 447 #define _MD_UNLOCK(lock) 448 #define _MD_INIT_IO() 449 #define _MD_IOQ_LOCK() 450 #define _MD_IOQ_UNLOCK() 451 452 #define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) 453 #define _MD_INIT_THREAD _MD_InitializeThread 454 #define _MD_EXIT_THREAD(thread) 455 #define _MD_SUSPEND_THREAD(thread) 456 #define _MD_RESUME_THREAD(thread) 457 #define _MD_CLEAN_THREAD(_thread) 458 459 extern PRStatus _MD_WAIT(struct PRThread *, PRIntervalTime timeout); 460 extern PRStatus _MD_WAKEUP_WAITER(struct PRThread *); 461 extern void _MD_YIELD(void); 462 extern PRStatus _MD_InitializeThread(PRThread *thread); 463 extern void _MD_SET_PRIORITY(struct _MDThread *thread, 464 PRThreadPriority newPri); 465 extern PRStatus _MD_CREATE_THREAD(PRThread *thread, void (*start) (void *), 466 PRThreadPriority priority, PRThreadScope scope, PRThreadState state, 467 PRUint32 stackSize); 468 469 /* The following defines the unwrapped versions of select() and poll(). */ 470 extern int _select(int nfds, fd_set *readfds, fd_set *writefds, 471 fd_set *exceptfds, struct timeval *timeout); 472 #define _MD_SELECT _select 473 474 #include <stropts.h> 475 #include <poll.h> 476 #define _MD_POLL _poll 477 extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); 478 479 PR_BEGIN_EXTERN_C 480 481 /* 482 ** Missing function prototypes 483 */ 484 extern int gethostname (char *name, int namelen); 485 486 PR_END_EXTERN_C 487 488 #endif /* _PR_PTHREADS */ 489 490 extern void _MD_solaris_map_sendfile_error(int err); 491 492 #endif /* nspr_solaris_defs_h___ */ 493 494