OSDN Git Service

* include/private/gc_locks.h [IA64]: Include ia64intrin.h.
[pf3gnuchains/gcc-fork.git] / boehm-gc / include / private / gc_locks.h
1 /* 
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
5  * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
6  *
7  *
8  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
9  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
10  *
11  * Permission is hereby granted to use or copy this program
12  * for any purpose,  provided the above notices are retained on all copies.
13  * Permission to modify the code and to distribute modified code is granted,
14  * provided the above notices are retained, and a notice that the code was
15  * modified is included with the above copyright notice.
16  */
17
18 #ifndef GC_LOCKS_H
19 #define GC_LOCKS_H
20
21 /*
22  * Mutual exclusion between allocator/collector routines.
23  * Needed if there is more than one allocator thread.
24  * FASTLOCK() is assumed to try to acquire the lock in a cheap and
25  * dirty way that is acceptable for a few instructions, e.g. by
26  * inhibiting preemption.  This is assumed to have succeeded only
27  * if a subsequent call to FASTLOCK_SUCCEEDED() returns TRUE.
28  * FASTUNLOCK() is called whether or not FASTLOCK_SUCCEEDED().
29  * If signals cannot be tolerated with the FASTLOCK held, then
30  * FASTLOCK should disable signals.  The code executed under
31  * FASTLOCK is otherwise immune to interruption, provided it is
32  * not restarted.
33  * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK
34  * and/or DISABLE_SIGNALS and ENABLE_SIGNALS and/or FASTLOCK.
35  * (There is currently no equivalent for FASTLOCK.)
36  *
37  * In the PARALLEL_MARK case, we also need to define a number of
38  * other inline finctions here:
39  *   GC_bool GC_compare_and_exchange( volatile GC_word *addr,
40  *                                    GC_word old, GC_word new )
41  *   GC_word GC_atomic_add( volatile GC_word *addr, GC_word how_much )
42  *   void GC_memory_barrier( )
43  *   
44  */  
45 # ifdef THREADS
46    void GC_noop1 GC_PROTO((word));
47 #  ifdef PCR_OBSOLETE   /* Faster, but broken with multiple lwp's       */
48 #    include  "th/PCR_Th.h"
49 #    include  "th/PCR_ThCrSec.h"
50      extern struct PCR_Th_MLRep GC_allocate_ml;
51 #    define DCL_LOCK_STATE  PCR_sigset_t GC_old_sig_mask
52 #    define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) 
53 #    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
54 #    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
55 #    define FASTLOCK() PCR_ThCrSec_EnterSys()
56      /* Here we cheat (a lot): */
57 #        define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0)
58                 /* TRUE if nobody currently holds the lock */
59 #    define FASTUNLOCK() PCR_ThCrSec_ExitSys()
60 #  endif
61 #  ifdef PCR
62 #    include <base/PCR_Base.h>
63 #    include <th/PCR_Th.h>
64      extern PCR_Th_ML GC_allocate_ml;
65 #    define DCL_LOCK_STATE \
66          PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
67 #    define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
68 #    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
69 #    define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml))
70 #    define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay)
71 #    define FASTUNLOCK()  {\
72         if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); }
73 #  endif
74 #  ifdef SRC_M3
75      extern GC_word RT0u__inCritical;
76 #    define LOCK() RT0u__inCritical++
77 #    define UNLOCK() RT0u__inCritical--
78 #  endif
79 #  ifdef GC_SOLARIS_THREADS
80 #    include <thread.h>
81 #    include <signal.h>
82      extern mutex_t GC_allocate_ml;
83 #    define LOCK() mutex_lock(&GC_allocate_ml);
84 #    define UNLOCK() mutex_unlock(&GC_allocate_ml);
85 #  endif
86
87 /* Try to define GC_TEST_AND_SET and a matching GC_CLEAR for spin lock  */
88 /* acquisition and release.  We need this for correct operation of the  */
89 /* incremental GC.                                                      */
90 #  ifdef __GNUC__
91 #    if defined(I386)
92        inline static int GC_test_and_set(volatile unsigned int *addr) {
93           int oldval;
94           /* Note: the "xchg" instruction does not need a "lock" prefix */
95           __asm__ __volatile__("xchgl %0, %1"
96                 : "=r"(oldval), "=m"(*(addr))
97                 : "0"(1), "m"(*(addr)) : "memory");
98           return oldval;
99        }
100 #      define GC_TEST_AND_SET_DEFINED
101 #    endif
102 #    if defined(IA64)
103 #     include <ia64intrin.h>
104        inline static int GC_test_and_set(volatile unsigned int *addr) {
105           return __sync_lock_test_and_set(addr, 1);
106        }
107 #      define GC_TEST_AND_SET_DEFINED
108        inline static void GC_clear(volatile unsigned int *addr) {
109           *addr = 0;
110        }
111 #      define GC_CLEAR_DEFINED
112 #    endif
113 #    ifdef SPARC
114        inline static int GC_test_and_set(volatile unsigned int *addr) {
115          int oldval;
116
117          __asm__ __volatile__("ldstub %1,%0"
118          : "=r"(oldval), "=m"(*addr)
119          : "m"(*addr) : "memory");
120          return oldval;
121        }
122 #      define GC_TEST_AND_SET_DEFINED
123 #    endif
124 #    ifdef M68K
125        /* Contributed by Tony Mantler.  I'm not sure how well it was    */
126        /* tested.                                                       */
127        inline static int GC_test_and_set(volatile unsigned int *addr) {
128           char oldval; /* this must be no longer than 8 bits */
129
130           /* The return value is semi-phony. */
131           /* 'tas' sets bit 7 while the return */
132           /* value pretends bit 0 was set */
133           __asm__ __volatile__(
134                  "tas %1@; sne %0; negb %0"
135                  : "=d" (oldval)
136                  : "a" (addr) : "memory");
137           return oldval;
138        }
139 #      define GC_TEST_AND_SET_DEFINED
140 #    endif
141 #    if defined(POWERPC)
142         inline static int GC_test_and_set(volatile unsigned int *addr) {
143           int oldval;
144           int temp = 1; // locked value
145
146           __asm__ __volatile__(
147                "1:\tlwarx %0,0,%3\n"   // load and reserve
148                "\tcmpwi %0, 0\n"       // if load is
149                "\tbne 2f\n"            //   non-zero, return already set
150                "\tstwcx. %2,0,%1\n"    // else store conditional
151                "\tbne- 1b\n"           // retry if lost reservation
152                "2:\t\n"                // oldval is zero if we set
153               : "=&r"(oldval), "=p"(addr)
154               : "r"(temp), "1"(addr)
155               : "memory");
156           return (int)oldval;
157         }
158 #       define GC_TEST_AND_SET_DEFINED
159         inline static void GC_clear(volatile unsigned int *addr) {
160           __asm__ __volatile__("eieio" ::: "memory");
161           *(addr) = 0;
162         }
163 #       define GC_CLEAR_DEFINED
164 #    endif
165 #    if defined(ALPHA) 
166         inline static int GC_test_and_set(volatile unsigned int * addr)
167         {
168           unsigned long oldvalue;
169           unsigned long temp;
170
171           __asm__ __volatile__(
172                              "1:     ldl_l %0,%1\n"
173                              "       and %0,%3,%2\n"
174                              "       bne %2,2f\n"
175                              "       xor %0,%3,%0\n"
176                              "       stl_c %0,%1\n"
177                              "       beq %0,3f\n"
178                              "       mb\n"
179                              "2:\n"
180                              ".section .text2,\"ax\"\n"
181                              "3:     br 1b\n"
182                              ".previous"
183                              :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
184                              :"Ir" (1), "m" (*addr)
185                              :"memory");
186
187           return oldvalue;
188         }
189 #       define GC_TEST_AND_SET_DEFINED
190         /* Should probably also define GC_clear, since it needs */
191         /* a memory barrier ??                                  */
192 #    endif /* ALPHA */
193 #    ifdef ARM32
194         inline static int GC_test_and_set(volatile unsigned int *addr) {
195           int oldval;
196           /* SWP on ARM is very similar to XCHG on x86.  Doesn't lock the
197            * bus because there are no SMP ARM machines.  If/when there are,
198            * this code will likely need to be updated. */
199           /* See linuxthreads/sysdeps/arm/pt-machine.h in glibc-2.1 */
200           __asm__ __volatile__("swp %0, %1, [%2]"
201                              : "=r"(oldval)
202                              : "r"(1), "r"(addr)
203                              : "memory");
204           return oldval;
205         }
206 #       define GC_TEST_AND_SET_DEFINED
207 #    endif /* ARM32 */
208 #    ifdef S390
209         inline static int GC_test_and_set(volatile unsigned int *addr) {
210          int ret;
211          __asm__ __volatile__ (
212                 "       l       %0,0(%2)\n"
213                 "0:     cs      %0,%1,0(%2)\n"
214                 "       jl      0b"
215                 : "=&d" (ret)
216                 : "d" (1), "a" (addr)
217                 : "cc", "memory");
218           return ret;
219         }
220 #    endif
221 #  endif /* __GNUC__ */
222 #  if (defined(ALPHA) && !defined(__GNUC__))
223 #    define GC_test_and_set(addr) __cxx_test_and_set_atomic(addr, 1)
224 #    define GC_TEST_AND_SET_DEFINED
225 #  endif
226 #  if defined(MSWIN32)
227 #    define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
228 #    define GC_TEST_AND_SET_DEFINED
229 #  endif
230 #  ifdef MIPS
231 #    ifdef LINUX
232 #      include <sys/tas.h>
233 #      define GC_test_and_set(addr) _test_and_set((int *) addr,1)
234 #      define GC_TEST_AND_SET_DEFINED
235 #    elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
236         || !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
237 #        define GC_test_and_set(addr) test_and_set(addr, 1)
238 #    else
239 #        define GC_test_and_set(addr) __test_and_set(addr,1)
240 #        define GC_clear(addr) __lock_release(addr);
241 #        define GC_CLEAR_DEFINED
242 #    endif
243 #    define GC_TEST_AND_SET_DEFINED
244 #  endif /* MIPS */
245 #  if 0 /* defined(HP_PA) */
246      /* The official recommendation seems to be to not use ldcw from    */
247      /* user mode.  Since multithreaded incremental collection doesn't  */
248      /* work anyway on HP_PA, this shouldn't be a major loss.           */
249
250      /* "set" means 0 and "clear" means 1 here.         */
251 #    define GC_test_and_set(addr) !GC_test_and_clear(addr);
252 #    define GC_TEST_AND_SET_DEFINED
253 #    define GC_clear(addr) GC_noop1((word)(addr)); *(volatile unsigned int *)addr = 1;
254         /* The above needs a memory barrier! */
255 #    define GC_CLEAR_DEFINED
256 #  endif
257 #  if defined(GC_TEST_AND_SET_DEFINED) && !defined(GC_CLEAR_DEFINED)
258 #    ifdef __GNUC__
259        inline static void GC_clear(volatile unsigned int *addr) {
260          /* Try to discourage gcc from moving anything past this. */
261          __asm__ __volatile__(" " : : : "memory");
262          *(addr) = 0;
263        }
264 #    else
265             /* The function call in the following should prevent the    */
266             /* compiler from moving assignments to below the UNLOCK.    */
267 #      define GC_clear(addr) GC_noop1((word)(addr)); \
268                              *((volatile unsigned int *)(addr)) = 0;
269 #    endif
270 #    define GC_CLEAR_DEFINED
271 #  endif /* !GC_CLEAR_DEFINED */
272
273 #  if !defined(GC_TEST_AND_SET_DEFINED)
274 #    define USE_PTHREAD_LOCKS
275 #  endif
276
277 #  if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
278       && !defined(GC_IRIX_THREADS)
279 #    define NO_THREAD (pthread_t)(-1)
280 #    include <pthread.h>
281 #    if defined(PARALLEL_MARK) 
282       /* We need compare-and-swap to update mark bits, where it's       */
283       /* performance critical.  If USE_MARK_BYTES is defined, it is     */
284       /* no longer needed for this purpose.  However we use it in       */
285       /* either case to implement atomic fetch-and-add, though that's   */
286       /* less performance critical, and could perhaps be done with      */
287       /* a lock.                                                        */
288 #     if defined(GENERIC_COMPARE_AND_SWAP)
289         /* Probably not useful, except for debugging.   */
290         /* We do use GENERIC_COMPARE_AND_SWAP on PA_RISC, but we        */
291         /* minimize its use.                                            */
292         extern pthread_mutex_t GC_compare_and_swap_lock;
293
294         /* Note that if GC_word updates are not atomic, a concurrent    */
295         /* reader should acquire GC_compare_and_swap_lock.  On          */
296         /* currently supported platforms, such updates are atomic.      */
297         extern GC_bool GC_compare_and_exchange(volatile GC_word *addr,
298                                                GC_word old, GC_word new_val);
299 #     endif /* GENERIC_COMPARE_AND_SWAP */
300 #     if defined(I386)
301 #      if !defined(GENERIC_COMPARE_AND_SWAP)
302          /* Returns TRUE if the comparison succeeded. */
303          inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
304                                                        GC_word old,
305                                                        GC_word new_val) 
306          {
307            char result;
308            __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
309                 : "=m"(*(addr)), "=r"(result)
310                 : "r" (new_val), "0"(*(addr)), "a"(old) : "memory");
311            return (GC_bool) result;
312          }
313 #      endif /* !GENERIC_COMPARE_AND_SWAP */
314        inline static void GC_memory_write_barrier()
315        {
316          /* We believe the processor ensures at least processor */
317          /* consistent ordering.  Thus a compiler barrier       */
318          /* should suffice.                                     */
319          __asm__ __volatile__("" : : : "memory");
320        }
321 #     endif /* I386 */
322 #     if defined(IA64)
323 #      if !defined(GENERIC_COMPARE_AND_SWAP)
324          inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
325                                                        GC_word old,
326                                                        GC_word new_val) 
327          {
328            return __sync_bool_compare_and_swap (addr, old, new_val);
329          }
330 #      endif /* !GENERIC_COMPARE_AND_SWAP */
331 #      if 0
332         /* Shouldn't be needed; we use volatile stores instead. */
333         inline static void GC_memory_write_barrier()
334         {
335           __sync_synchronize ();
336         }
337 #      endif /* 0 */
338 #     endif /* IA64 */
339 #     if defined(S390)
340 #      if !defined(GENERIC_COMPARE_AND_SWAP)
341          inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
342                                                        GC_word old, GC_word new_val) 
343          {
344            int retval;
345            __asm__ __volatile__ (
346 #          ifndef __s390x__
347                 "       cs  %1,%2,0(%3)\n"
348 #          else
349                 "       csg %1,%2,0(%3)\n"
350 #          endif
351                 "       ipm %0\n"
352                 "       srl %0,28\n"
353                 : "=&d" (retval), "+d" (old)
354                 : "d" (new_val), "a" (addr)
355                 : "cc", "memory");
356            return retval == 0;
357         }
358 #      endif
359 #     endif
360 #     if !defined(GENERIC_COMPARE_AND_SWAP)
361         /* Returns the original value of *addr. */
362         inline static GC_word GC_atomic_add(volatile GC_word *addr,
363                                             GC_word how_much)
364         {
365           GC_word old;
366           do {
367             old = *addr;
368           } while (!GC_compare_and_exchange(addr, old, old+how_much));
369           return old;
370         }
371 #     else /* GENERIC_COMPARE_AND_SWAP */
372         /* So long as a GC_word can be atomically updated, it should    */
373         /* be OK to read *addr without a lock.                          */
374         extern GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much);
375 #     endif /* GENERIC_COMPARE_AND_SWAP */
376
377 #    endif /* PARALLEL_MARK */
378
379 #    if !defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_LOCKS)
380       /* In the THREAD_LOCAL_ALLOC case, the allocation lock tends to   */
381       /* be held for long periods, if it is held at all.  Thus spinning */
382       /* and sleeping for fixed periods are likely to result in         */
383       /* significant wasted time.  We thus rely mostly on queued locks. */
384 #     define USE_SPIN_LOCK
385       extern volatile unsigned int GC_allocate_lock;
386       extern void GC_lock(void);
387         /* Allocation lock holder.  Only set if acquired by client through */
388         /* GC_call_with_alloc_lock.                                        */
389 #     ifdef GC_ASSERTIONS
390 #        define LOCK() \
391                 { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); \
392                   SET_LOCK_HOLDER(); }
393 #        define UNLOCK() \
394                 { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
395                   GC_clear(&GC_allocate_lock); }
396 #     else
397 #        define LOCK() \
398                 { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
399 #        define UNLOCK() \
400                 GC_clear(&GC_allocate_lock)
401 #     endif /* !GC_ASSERTIONS */
402 #     if 0
403         /* Another alternative for OSF1 might be:               */
404 #       include <sys/mman.h>
405         extern msemaphore GC_allocate_semaphore;
406 #       define LOCK() { if (msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) \
407                             != 0) GC_lock(); else GC_allocate_lock = 1; }
408         /* The following is INCORRECT, since the memory model is too weak. */
409         /* Is this true?  Presumably msem_unlock has the right semantics?  */
410         /*              - HB                                               */
411 #       define UNLOCK() { GC_allocate_lock = 0; \
412                           msem_unlock(&GC_allocate_semaphore, 0); }
413 #     endif /* 0 */
414 #    else /* THREAD_LOCAL_ALLOC  || USE_PTHREAD_LOCKS */
415 #      ifndef USE_PTHREAD_LOCKS
416 #        define USE_PTHREAD_LOCKS
417 #      endif
418 #    endif /* THREAD_LOCAL_ALLOC */
419 #   ifdef USE_PTHREAD_LOCKS
420 #      include <pthread.h>
421        extern pthread_mutex_t GC_allocate_ml;
422 #      ifdef GC_ASSERTIONS
423 #        define LOCK() \
424                 { GC_lock(); \
425                   SET_LOCK_HOLDER(); }
426 #        define UNLOCK() \
427                 { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
428                   pthread_mutex_unlock(&GC_allocate_ml); }
429 #      else /* !GC_ASSERTIONS */
430 #        define LOCK() \
431            { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
432 #        define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
433 #      endif /* !GC_ASSERTIONS */
434 #   endif /* USE_PTHREAD_LOCKS */
435 #   define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
436 #   define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
437 #   define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
438     extern VOLATILE GC_bool GC_collecting;
439 #   define ENTER_GC() GC_collecting = 1;
440 #   define EXIT_GC() GC_collecting = 0;
441     extern void GC_lock(void);
442     extern pthread_t GC_lock_holder;
443 #   ifdef GC_ASSERTIONS
444       extern pthread_t GC_mark_lock_holder;
445 #   endif
446 #  endif /* GC_PTHREADS with linux_threads.c implementation */
447 #  if defined(GC_IRIX_THREADS)
448 #    include <pthread.h>
449      /* This probably should never be included, but I can't test        */
450      /* on Irix anymore.                                                */
451 #    include <mutex.h>
452
453      extern unsigned long GC_allocate_lock;
454         /* This is not a mutex because mutexes that obey the (optional)         */
455         /* POSIX scheduling rules are subject to convoys in high contention     */
456         /* applications.  This is basically a spin lock.                        */
457      extern pthread_t GC_lock_holder;
458      extern void GC_lock(void);
459         /* Allocation lock holder.  Only set if acquired by client through */
460         /* GC_call_with_alloc_lock.                                        */
461 #    define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
462 #    define NO_THREAD (pthread_t)(-1)
463 #    define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
464 #    define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
465 #    define LOCK() { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
466 #    define UNLOCK() GC_clear(&GC_allocate_lock);
467      extern VOLATILE GC_bool GC_collecting;
468 #    define ENTER_GC() \
469                 { \
470                     GC_collecting = 1; \
471                 }
472 #    define EXIT_GC() GC_collecting = 0;
473 #  endif /* GC_IRIX_THREADS */
474 #  ifdef GC_WIN32_THREADS
475 #    include <windows.h>
476      GC_API CRITICAL_SECTION GC_allocate_ml;
477 #    define LOCK() EnterCriticalSection(&GC_allocate_ml);
478 #    define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
479 #  endif
480 #  ifndef SET_LOCK_HOLDER
481 #      define SET_LOCK_HOLDER()
482 #      define UNSET_LOCK_HOLDER()
483 #      define I_HOLD_LOCK() FALSE
484                 /* Used on platforms were locks can be reacquired,      */
485                 /* so it doesn't matter if we lie.                      */
486 #  endif
487 # else /* !THREADS */
488 #    define LOCK()
489 #    define UNLOCK()
490 # endif /* !THREADS */
491 # ifndef SET_LOCK_HOLDER
492 #   define SET_LOCK_HOLDER()
493 #   define UNSET_LOCK_HOLDER()
494 #   define I_HOLD_LOCK() FALSE
495                 /* Used on platforms were locks can be reacquired,      */
496                 /* so it doesn't matter if we lie.                      */
497 # endif
498 # ifndef ENTER_GC
499 #   define ENTER_GC()
500 #   define EXIT_GC()
501 # endif
502
503 # ifndef DCL_LOCK_STATE
504 #   define DCL_LOCK_STATE
505 # endif
506 # ifndef FASTLOCK
507 #   define FASTLOCK() LOCK()
508 #   define FASTLOCK_SUCCEEDED() TRUE
509 #   define FASTUNLOCK() UNLOCK()
510 # endif
511
512 #endif /* GC_LOCKS_H */