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