1 /* Copyright (C) 2002, 2003, 2004, 2005, 2009 Free Software Foundation, Inc. 2 Contributed by Zack Weinberg <zack@codesourcery.com> 3 4 This file is part of GCC. 5 6 GCC is free software; you can redistribute it and/or modify it under 7 the terms of the GNU General Public License as published by the Free 8 Software Foundation; either version 3, or (at your option) any later 9 version. 10 11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 for more details. 15 16 Under Section 7 of GPL version 3, you are granted additional 17 permissions described in the GCC Runtime Library Exception, version 18 3.1, as published by the Free Software Foundation. 19 20 You should have received a copy of the GNU General Public License and 21 a copy of the GCC Runtime Library Exception along with this program; 22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 <http://www.gnu.org/licenses/>. */ 24 25 /* Threads compatibility routines for libgcc2 for VxWorks. 26 These are out-of-line routines called from gthr-vxworks.h. */ 27 28 #include "tconfig.h" 29 #include "tsystem.h" 30 #include "gthr.h" 31 32 #if defined(__GTHREADS) 33 #include <vxWorks.h> 34 #ifndef __RTP__ 35 #include <vxLib.h> 36 #endif 37 #include <taskLib.h> 38 #ifndef __RTP__ 39 #include <taskHookLib.h> 40 #else 41 # include <errno.h> 42 #endif 43 44 /* Init-once operation. 45 46 This would be a clone of the implementation from gthr-solaris.h, 47 except that we have a bootstrap problem - the whole point of this 48 exercise is to prevent double initialization, but if two threads 49 are racing with each other, once->mutex is liable to be initialized 50 by both. Then each thread will lock its own mutex, and proceed to 51 call the initialization routine. 52 53 So instead we use a bare atomic primitive (vxTas()) to handle 54 mutual exclusion. Threads losing the race then busy-wait, calling 55 taskDelay() to yield the processor, until the initialization is 56 completed. Inefficient, but reliable. */ 57 58 int 59 __gthread_once (__gthread_once_t *guard, void (*func)(void)) 60 { 61 if (guard->done) 62 return 0; 63 64 #ifdef __RTP__ 65 __gthread_lock_library (); 66 #else 67 while (!vxTas ((void *)&guard->busy)) 68 { 69 #ifdef __PPC__ 70 /* This can happen on powerpc, which is using all 32 bits 71 of the gthread_once_t structure. */ 72 if (guard->done) 73 return; 74 #endif 75 taskDelay (1); 76 } 77 #endif 78 79 /* Only one thread at a time gets here. Check ->done again, then 80 go ahead and call func() if no one has done it yet. */ 81 if (!guard->done) 82 { 83 func (); 84 guard->done = 1; 85 } 86 87 #ifdef __RTP__ 88 __gthread_unlock_library (); 89 #else 90 guard->busy = 0; 91 #endif 92 return 0; 93 } 94 95 #endif /* __GTHREADS */ 96