1 /*
2     sysdep.h:
3 
4     Copyright (C) 1991 Barry Vercoe, John ffitch
5 
6     This file is part of Csound.
7 
8     The Csound Library is free software; you can redistribute it
9     and/or modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation; either
11     version 2.1 of the License, or (at your option) any later version.
12 
13     Csound is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with Csound; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21     02110-1301 USA
22 */
23 
24 #ifndef CSOUND_SYSDEP_H
25 #define CSOUND_SYSDEP_H
26 
27 /* check for the presence of a modern compiler (for use of certain features) */
28 #if defined(WIN32)
29 #if !defined(locale_t)
30 typedef void *locale_t;
31 #endif
32 #endif
33 
34 #include <limits.h>
35 /* this checks for 64BIT builds */
36 #if defined(__MACH__) || defined(LINUX)
37 #if ( __WORDSIZE == 64 ) || defined(__x86_64__) || defined(__amd64__)
38 #define B64BIT
39 #endif
40 #endif
41 
42 #if defined(WIN32)
43 #if _WIN64
44 #define B64BIT
45 #endif
46 #endif
47 
48 
49 
50 #ifdef HAVE_GCC3
51 #  undef HAVE_GCC3
52 #endif
53 #ifdef HAVE_C99
54 #  undef HAVE_C99
55 #endif
56 #if (defined(__GNUC__) && (__GNUC__ >= 3))
57 #  define HAVE_C99 1
58 #  if defined(__BUILDING_LIBCSOUND) || defined(CSOUND_CSDL_H)
59 #    ifndef _ISOC99_SOURCE
60 #      define _ISOC99_SOURCE  1
61 #    endif
62 #    ifndef _ISOC9X_SOURCE
63 #      define _ISOC9X_SOURCE  1
64 #    endif
65 #  endif
66 #  if !(defined(__MACH__) && (__GNUC__ == 3) && (__GNUC_MINOR__ < 2))
67 #    define HAVE_GCC3 1
68 #  endif
69 #elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
70 #  define HAVE_C99 1
71 #endif
72 
73 #if defined(__GNUC__)
74 # if defined(__GNUC_PATCHLEVEL__)
75 #  define __GNUC_VERSION__ (__GNUC__ * 10000 \
76                             + __GNUC_MINOR__ * 100 \
77                             + __GNUC_PATCHLEVEL__)
78 # else
79 #  define __GNUC_VERSION__ (__GNUC__ * 10000 \
80                             + __GNUC_MINOR__ * 100)
81 # endif
82 #endif
83 
84 #ifndef CABBAGE
85 #ifdef MSVC
86 typedef __int32 int32;
87 typedef __int16 int16;
88 typedef unsigned __int32 uint32;
89 typedef unsigned __int16 uint16;
90 #else
91 #include <stdint.h>
92 #if defined(__HAIKU__) && defined(__HAIKU_CONFLICT)
93  /* Haiku has different typedefs -- relevant to rthaiku and network*/
94  #include <SupportDefs.h>
95 #else
96 typedef int_least32_t int32;
97 typedef int_least16_t int16;
98 typedef uint_least32_t uint32;
99 typedef uint_least16_t uint16;
100 #endif
101 #endif
102 #endif
103 
104 #if defined(HAVE_PTHREAD_SPIN_LOCK)
105 #include <pthread.h>
106 #endif
107 
108 #ifdef __MACH__
109 #include <AvailabilityMacros.h>
110 #endif
111 
112 #if !defined(USE_DOUBLE)
113 #if !defined(_MSC_VER)
114 #include "float-version.h"
115 #else
116 #define USE_DOUBLE
117 #endif
118 #endif
119 
120 #ifdef USE_DOUBLE
121 /* Defined here as Android does not have log2 functions */
122 #define MYRECIPLN2  1.442695040888963407359924681001892137426 /* 1.0/log(2) */
123 #define LOG2(a) (MYRECIPLN2*log(a))       /* floating point logarithm base 2 */
124 
125   #define ACOS acos
126   #define ASIN asin
127   #define ATAN atan
128   #define ATAN2 atan2
129   #define COS cos
130   #define SIN sin
131   #define TAN tan
132   #define COSH cosh
133   #define SINH sinh
134   #define TANH tanh
135   #define ACOSH acosh
136   #define ASINH asinh
137   #define ATANH atanh
138   #define EXP exp
139   #define LOG log
140   #define LOG10 log10
141   /* #define LOG2 log2 */
142   #define POWER pow
143   #define SQRT sqrt
144   #define HYPOT hypot
145   #define FABS fabs
146   #define FLOOR floor
147   #define CEIL ceil
148   #define FMOD fmod
149   #define MODF modf
150 #else
151 /* Defined here as Android does not have log2 functions */
152 #define MYRECIPLN2  1.442695040888963407359924681001892137426 /* 1.0/log(2) */
153 #define LOG2(a) (MYRECIPLN2*logf(a))       /* floating point logarithm base 2 */
154 
155   #define ACOS acosf
156   #define ASIN asinf
157   #define ATAN atanf
158   #define ATAN2 atan2f
159   #define COS cosf
160   #define SIN sinf
161   #define TAN tanf
162   #define COSH coshf
163   #define SINH sinhf
164   #define TANH tanhf
165   #define ACOSH acoshf
166   #define ASINH asinhf
167   #define ATANH atanhf
168   #define EXP expf
169   #define LOG logf
170   #define LOG10 log10f
171   /* #define LOG2 log2f */
172   #define POWER powf
173   #define SQRT sqrtf
174   #define HYPOT hypotf
175   #define FABS(x) fabsf(FL(x))
176   #define FLOOR floorf
177   #define CEIL ceilf
178   #define FMOD fmodf
179   #define MODF modff
180 #endif
181 
182 #include <stdio.h>
183 #include <stdlib.h>
184 #include <math.h>
185 #include <string.h>
186 #if defined(HAVE_FCNTL_H) || defined(__unix) || defined(__unix__)
187 #include <fcntl.h>
188 #endif
189 #if defined(HAVE_UNISTD_H) || defined(__unix) || defined(__unix__)
190 #include <unistd.h>
191 #endif
192 
193 /* Experiment with doubles or floats */
194 
195 #ifndef __MYFLT_DEF
196 #  define __MYFLT_DEF
197 #  ifndef USE_DOUBLE
198 #    define MYFLT float
199 #  else
200 #    define MYFLT double
201 #  endif
202 #endif
203 
204 /* Aligning to double boundaries, should work with MYFLT as float or double */
205 #define CS_FLOAT_ALIGN(x) ((int)(x + 7) & (~7))
206 
207 #if defined(__BUILDING_LIBCSOUND) || defined(CSOUND_CSDL_H)
208 
209 #define FL(x) ((MYFLT) (x))
210 
211 /* find out operating system if not specified on the command line */
212 
213 #if defined(_WIN32) || defined(__WIN32__)
214 #  ifndef WIN32
215 #    define WIN32 1
216 #  endif
217 #elif (defined(linux) || defined(__linux)) && !defined(LINUX)
218 #  define LINUX 1
219 #endif
220 
221 #if defined(WIN32) && defined(_MSC_VER) && !defined(__GNUC__)
222 #  ifndef MSVC
223 #    define MSVC 1
224 #  endif
225 #elif defined(MSVC)
226 #  undef MSVC
227 #endif
228 
229 /* inline keyword: always available in C++, C99, and GCC 3.x and above */
230 /* add any other compiler that supports 'inline' */
231 
232 #if !(defined(__cplusplus) || defined(inline))
233 #  if defined(HAVE_C99) || defined(HAVE_GCC3)
234 #    if defined(__GNUC__) && defined(__STRICT_ANSI__)
235 #      define inline __inline__
236 #    endif
237 #  elif defined(MSVC)
238 #    define inline  __inline
239 #  else
240 #    define inline
241 #  endif
242 #endif
243 
244 #define DIRSEP '/'
245 #ifdef WIN32
246 #  undef  DIRSEP
247 #  define DIRSEP '\\'
248 #  if !defined(O_NDELAY)
249 #    define  O_NDELAY (0)
250 #  endif
251 #  include <io.h>
252 #else
253 #  ifdef DOSGCC
254 #    if !defined(O_NDELAY)
255 #      define  O_NDELAY (0)
256 #    endif
257 #  endif
258 #  ifdef HAVE_SYS_TYPES_H
259 #    include <sys/types.h>
260 #  endif
261 /*  RWD for WIN32 on VC++ */
262 #endif
263 #ifndef MSVC
264 #  include <sys/file.h>
265 #endif
266 #include <sys/stat.h>
267 
268 #endif  /* __BUILDING_LIBCSOUND || CSOUND_CSDL_H */
269 
270 #ifdef WIN32
271 #  define ENVSEP ';'
272 #else
273 #  define ENVSEP ':'
274 #endif
275 /* standard integer types */
276 
277 #if defined(USE_GUSI2)
278 /* When compiling with GUSI on MacOS 9 (for Python),  */
279 /* all of the other integer types are already defined */
280 typedef int64_t             int_least64_t;
281 typedef uint64_t            uint_least64_t;
282 #elif defined(HAVE_STDINT_H) || defined(HAVE_C99)
283 #  include <stdint.h>
284 
285 #    if defined(__CYGWIN__)
286 #define __int8 char
287 #define __int16 short
288 #define __int32 int
289 #define __int64 long long
290 #    endif
291 #else
292 typedef signed char         int8_t;
293 typedef unsigned char       uint8_t;
294 typedef short               int16_t;
295 typedef unsigned short      uint16_t;
296 typedef int                 int32_t;
297 typedef unsigned int        uint32_t;
298 #  if defined(__GNUC__) || !defined(WIN32)
299 typedef long long           int64_t;
300 typedef unsigned long long  uint64_t;
301 typedef long long           int_least64_t;
302 typedef unsigned long long  uint_least64_t;
303 #  else
304 typedef __int64             int64_t;
305 typedef unsigned __int64    uint64_t;
306 typedef __int64             int_least64_t;
307 typedef unsigned __int64    uint_least64_t;
308 #  endif
309 #if !defined(_MSC_VER)
310 typedef long                intptr_t;
311 typedef unsigned long       uintptr_t;
312 #endif
313 #endif      /* !(USE_GUSI2 || HAVE_STDINT_H || HAVE_C99) */
314 
315 
316 
317 /* function attributes */
318 
319 #if defined(HAVE_GCC3) && !defined(SWIG)
320 /* deprecated function, variable, or type that is to be removed eventually */
321 #  define CS_DEPRECATED __attribute__ ((__deprecated__))
322 /* a function that should not be inlined */
323 #  define CS_NOINLINE   __attribute__ ((__noinline__))
324 /* a function that never returns (e.g. csoundDie()) */
325 #  define CS_NORETURN   __attribute__ ((__noreturn__))
326 /* printf-style function with first argument as format string */
327 #  define CS_PRINTF1    __attribute__ ((__format__ (__printf__, 1, 2)))
328 /* printf-style function with second argument as format string */
329 #  define CS_PRINTF2    __attribute__ ((__format__ (__printf__, 2, 3)))
330 /* printf-style function with third argument as format string */
331 #  define CS_PRINTF3    __attribute__ ((__format__ (__printf__, 3, 4)))
332 /* a function with no side effects or dependencies on volatile data */
333 #  define CS_PURE       __attribute__ ((__pure__))
334 #else
335 #  define CS_DEPRECATED
336 #  define CS_NOINLINE
337 #  define CS_NORETURN
338 #  define CS_PRINTF1
339 #  define CS_PRINTF2
340 #  define CS_PRINTF3
341 #  define CS_PURE
342 #endif
343 #if defined(__clang__) ||  defined(HAVE_GCC3)
344 #  define LIKELY(x)     __builtin_expect(!!(x),1)
345 #  define UNLIKELY(x)   __builtin_expect(!!(x),0)
346 #else
347 #  define LIKELY(x)     x
348 #  define UNLIKELY(x)   x
349 #endif
350 
351 #if defined(__BUILDING_LIBCSOUND) || defined(CSOUND_CSDL_H)
352 
353 /* macros for converting floats to integers */
354 /* MYFLT2LONG: converts with unspecified rounding */
355 /* MYFLT2LRND: rounds to nearest integer */
356 
357 #ifdef USE_LRINT
358 #  ifndef USE_DOUBLE
359 #    define MYFLT2LONG(x) (x > LONG_MIN && x < LONG_MAX ? \
360                            (int32) lrintf((float) (x)) : 0)
361 #    define MYFLT2LRND(x) (x > LONG_MIN && x < LONG_MAX ? \
362                            (int32) lrintf((float) (x)) : 0)
363 #  else
364 #    define MYFLT2LONG(x) (x > LONG_MIN && x < LONG_MAX ? \
365                            (int32) lrint((double) (x)) : 0)
366 #    define MYFLT2LRND(x) (x > LONG_MIN && x < LONG_MAX ? \
367                            (int32) lrint((double) (x)) : 0)
368 #  endif
369 #elif defined(MSVC)
370 #include <emmintrin.h>
371 #  ifndef USE_DOUBLE
372 // From Agner Fog optimisation manuals p.144
MYFLT2LONG(float const x)373 static inline int MYFLT2LONG (float const x) {
374     return _mm_cvtss_si32 (_mm_load_ss (&x));
375 }
376 
MYFLT2LRND(float const x)377 static inline int MYFLT2LRND (float const x) {
378     return _mm_cvtss_si32 (_mm_load_ss (&x));
379 }
380 
381 #  else
MYFLT2LONG(double const x)382 static inline int MYFLT2LONG (double const x) {
383     return _mm_cvtsd_si32 (_mm_load_sd (&x));
384 }
385 
MYFLT2LRND(double const x)386 static inline int MYFLT2LRND (double const x) {
387     return _mm_cvtsd_si32 (_mm_load_sd (&x));
388 }
389 #  endif
390 #else
391 #  ifndef USE_DOUBLE
392 #    define MYFLT2LONG(x) ((int32) (x))
393 #    if defined(HAVE_GCC3) && defined(__i386__) && !defined(__ICC)
394 #      define MYFLT2LRND(x) ((int32) lrintf((float) (x)))
395 #    else
MYFLT2LRND(float fval)396 static inline int32 MYFLT2LRND(float fval)
397 {
398     return ((int32) (fval + (fval < 0.0f ? -0.5f : 0.5f)));
399 }
400 #    endif
401 #  else
402 #    define MYFLT2LONG(x) ((int32) (x))
403 #    if defined(HAVE_GCC3) && defined(__i386__) && !defined(__ICC)
404 #      define MYFLT2LRND(x) ((int32) lrint((double) (x)))
405 #    else
MYFLT2LRND(double fval)406 static inline int32 MYFLT2LRND(double fval)
407 {
408     return ((int32) (fval + (fval < 0.0 ? -0.5 : 0.5)));
409 }
410 #    endif
411 #  endif
412 #endif
413 
414 /* inline functions and macros for clamping denormals to zero */
415 
416 #if defined(__i386__) || defined(MSVC)
csoundUndenormalizeFloat(float x)417 static inline float csoundUndenormalizeFloat(float x)
418 {
419     volatile float  tmp = 1.0e-30f;
420     return ((x + 1.0e-30f) - tmp);
421 }
422 
csoundUndenormalizeDouble(double x)423 static inline double csoundUndenormalizeDouble(double x)
424 {
425     volatile double tmp = 1.0e-200;
426     return ((x + 1.0e-200) - tmp);
427 }
428 #else
429 #  define csoundUndenormalizeFloat(x)   x
430 #  define csoundUndenormalizeDouble(x)  x
431 #endif
432 
433 #ifndef USE_DOUBLE
434 #  define csoundUndenormalizeMYFLT      csoundUndenormalizeFloat
435 #else
436 #  define csoundUndenormalizeMYFLT      csoundUndenormalizeDouble
437 #endif
438 
439 #endif  /* __BUILDING_LIBCSOUND || CSOUND_CSDL_H */
440 
441 // This is wrong.....  needs thought
442 /* #ifdef HAVE_SPRINTF_L */
443 /* # define CS_SPRINTF sprintf_l */
444 /* #elseif HAVE__SPRINT_L */
445 /*   /\* this would be the case for the Windows locale aware function *\/ */
446 /* # define CS_SPRINTF _sprintf_l */
447 /* #else */
448 # define CS_SPRINTF cs_sprintf
449 # define CS_SSCANF cs_sscanf
450 /* #endif */
451 
452 #if !defined(HAVE_STRLCAT) && !defined(strlcat)
453 size_t strlcat(char *dst, const char *src, size_t siz);
454 #endif
455 char *strNcpy(char *dst, const char *src, size_t siz);
456 
457 /* atomics */
458 #if defined(MSVC)
459 #define ATOMIC_SET(var, val)  InterlockedExchange(&var, val);
460 #elif defined(HAVE_ATOMIC_BUILTIN)
461 #define ATOMIC_SET(var, val) __atomic_store_n(&var, val, __ATOMIC_SEQ_CST);
462 #else
463 #define ATOMIC_SET(var, val) var = val;
464 #endif
465 
466 #if defined(MSVC)
467 #define ATOMIC_SET8(var, val)  InterlockedExchange8(&var, val);
468 #elif defined(HAVE_ATOMIC_BUILTIN)
469 #define ATOMIC_SET8(var, val) __atomic_store_n(&var, val,__ATOMIC_SEQ_CST);
470 #else
471 #define ATOMIC_SET8(var, val) var = val;
472 #endif
473 
474 #ifdef MSVC
475 #define ATOMIC_GET(var) InterlockedExchangeAdd(&var, 0)
476 #elif defined(HAVE_ATOMIC_BUILTIN)
477 #define ATOMIC_GET(var) __atomic_load_n(&var, __ATOMIC_SEQ_CST)
478 #else
479 #define ATOMIC_GET(var) var
480 #endif
481 
482 #ifdef MSVC
483 #define ATOMIC_GET8(var) InterlockedExchangeAdd8(&var, 0)
484 #elif defined(HAVE_ATOMIC_BUILTIN)
485 #define ATOMIC_GET8(var) __atomic_load_n(&var, __ATOMIC_SEQ_CST)
486 #else
487 #define ATOMIC_GET8(var) var
488 #endif
489 
490 #ifdef MSVC
491 #define ATOMIC_DECR(var) InterlockedExchangeAdd(&var, -1)
492 #elif defined(HAVE_ATOMIC_BUILTIN)
493 #define ATOMIC_DECR(var) __atomic_sub_fetch(&var, 1, __ATOMIC_SEQ_CST)
494 #else
495 #define ATOMIC_DECR(var) var -= 1
496 #endif
497 
498 #ifdef MSVC
499 #define ATOMIC_INCR(var) InterlockedExchangeAdd(&var, 1)
500 #elif defined(HAVE_ATOMIC_BUILTIN)
501 #define ATOMIC_INCR(var) __atomic_add_fetch(&var, 1, __ATOMIC_SEQ_CST)
502 #else
503 #define ATOMIC_INCR(var) var += 1
504 #endif
505 
506 #ifdef MSVC
507 #define ATOMIC_SUB(var, val) InterlockedExchangeAdd(&var, -val)
508 #elif defined(HAVE_ATOMIC_BUILTIN)
509 #define ATOMIC_SUB(var, val) __atomic_sub_fetch(&var, val, __ATOMIC_SEQ_CST)
510 #else
511 #define ATOMIC_SUB(var, val) var -= val
512 #endif
513 
514 #ifdef MSVC
515 #define ATOMIC_ADD(var, val) InterlockedExchangeAdd(&var, val)
516 #elif defined(HAVE_ATOMIC_BUILTIN)
517 #define ATOMIC_ADD(var, val) __atomic_add_fetch(&var, val, __ATOMIC_SEQ_CST)
518 #else
519 #define ATOMIC_ADD(var, val) var += val
520 #endif
521 
522 #if defined(MSVC)
523 #define ATOMIC_CMP_XCH(val, newVal, oldVal) \
524   (InterlockedCompareExchange(val, newVal, oldVal) != oldVal)
525 #elif defined(HAVE_ATOMIC_BUILTIN)
526 #define ATOMIC_CMP_XCH(val, newVal, oldVal) \
527   !(__atomic_compare_exchange(val, (long *) &oldVal, &newVal, 0,        \
528                               __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
529 #else /* FIXME: no atomics, what to do? */
530 #define ATOMIC_CMP_XCH(val, newVal, oldVal) (*val = newVal) != oldVal
531 #endif
532 
533 #if defined(WIN32)
534 typedef int32_t spin_lock_t;
535 #define SPINLOCK_INIT 0
536 
537 #elif defined(MACOSX)
538 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
539 #include <os/lock.h>
540 typedef struct os_unfair_lock_s spin_lock_t;
541 #define SPINLOCK_INIT {0}
542 #else
543 #include <libkern/OSAtomic.h>
544 typedef int32_t spin_lock_t;
545 #define SPINLOCK_INIT 0
546 #endif // MAC_OS_X_VERSION_MIN_REQUIRED
547 
548 #elif defined(__GNUC__) && defined(HAVE_PTHREAD_SPIN_LOCK)
549 typedef pthread_spinlock_t spin_lock_t;
550 #define SPINLOCK_INIT PTHREAD_SPINLOCK_INITIALIZER
551 #elif defined(__GNUC__) && defined(HAVE_ATOMIC_BUILTIN)
552 typedef char spin_lock_t;
553 #define SPINLOCK_INIT 0
554 
555 #else
556 typedef int32_t spin_lock_t;
557 #define SPINLOCK_INIT 0
558 #endif
559 
560 /* The ignore_value() macro is taken from GNULIB ignore-value.h,
561    licensed under the terms of the LGPLv2+
562    Normally casting an expression to void discards its value, but GCC
563    versions 3.4 and newer have __attribute__ ((__warn_unused_result__))
564    which may cause unwanted diagnostics in that case.  Use __typeof__
565    and __extension__ to work around the problem, if the workaround is
566    known to be needed.  */
567 #if 3 < __GNUC__ + (4 <= __GNUC_MINOR__)
568 # define ignore_value(x) \
569     (__extension__ ({ __typeof__ (x) __x = (x); (void) __x; }))
570 #else
571 # define ignore_value(x) ((void) (x))
572 #endif
573 
574 
575 #endif  /* CSOUND_SYSDEP_H */
576