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