Merge trunk version 208609 into gupc branch.
[official-gcc.git] / libgupc / smp / upc_sysdep.c
blob18d7400a2488b85317543a05004801f5a7e07567
1 /* Copyright (C) 2003-2014 Free Software Foundation, Inc.
2 This file is part of the UPC runtime Library.
3 Written by Gary Funck <gary@intrepid.com>
4 and Nenad Vukicevic <nenad@intrepid.com>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2, or (at
9 your option) any later version.
11 This library is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this library; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA.
21 As a special exception, if you link this library with files
22 compiled with a GNU compiler to produce an executable, this does
23 not cause the resulting executable to be covered by the GNU General
24 Public License. This exception does not however invalidate any
25 other reasons why the executable file might be covered by the GNU
26 General Public License. */
28 #include "upc_config.h"
29 #include "upc_sysdep.h"
30 #include "upc_defs.h"
31 #include "upc_sup.h"
32 #include "upc_sync.h"
34 #ifdef __sgi__
35 #ifndef _SC_NPROCESSORS_ONLN
36 #define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
37 #endif
38 #endif
40 int __upc_num_cpus;
42 void
43 __upc_sys_init ()
45 __upc_num_cpus = (int) sysconf (_SC_NPROCESSORS_ONLN);
47 /* Make sure that this main process is the process group leader */
48 if (getpgrp() != getpid())
50 if (setpgid(0, 0) == -1)
51 { perror("setpgid"); exit (2); }
55 char *__upc_strsignal (sig)
56 int sig;
58 static char sigbuf[64];
59 #ifdef __sgi__
60 char **sys_siglist = _sys_siglist;
61 const int nsig = _sys_nsig;
62 #else
63 extern const char * const sys_siglist[];
64 const int nsig = NSIG;
65 #endif
66 if (sig > 0 && sig < nsig)
67 return (char *)sys_siglist[sig];
68 else
69 return (sprintf (sigbuf, "signal number %d", sig), sigbuf);
72 #ifndef __upc_atomic_cas
73 /* If a builtin implementation of __upc_atomic_cas was found,
74 then the symbol will be defined as a pre-processor macro.
75 Otherwise, implement the function out-of-line. */
76 #ifdef __sgi__
77 int
78 __upc_atomic_cas (os_atomic_p ptr, os_atomic_t old, os_atomic_t new)
80 upc_info_p u = __upc_info;
81 return uscas ((void *)ptr, old, new, (usptr_t *)u->runtime_heap);
83 #elif __i386__
85 #define LOCK_PREFIX "lock ; "
87 int
88 __upc_atomic_cas (os_atomic_p ptr, os_atomic_t old, os_atomic_t new)
90 os_atomic_t prev;
91 __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
92 : "=a"(prev)
93 : "q"(new), "m"(*ptr), "0"(old)
94 : "memory");
95 return prev == old;
97 #elif __x86_64__
99 #define LOCK_PREFIX "lock ; "
102 __upc_atomic_cas (os_atomic_p ptr, os_atomic_t old, os_atomic_t new)
104 os_atomic_t prev;
105 __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
106 : "=a"(prev)
107 : "q"(new), "m"(*ptr), "0"(old)
108 : "memory");
109 return prev == old;
112 #elif __ia64__
114 #include <linux/types.h>
115 #include <asm/intrinsics.h>
118 __upc_atomic_cas (os_atomic_p ptr, os_atomic_t old, os_atomic_t new)
120 os_atomic_t prev;
121 prev = cmpxchg (ptr, old, new);
122 return prev == old;
124 #else
125 #error "__upc_atomic_cas not implemented on this target"
126 #endif
127 #endif /* ! __upc_atomic_cas */
130 __upc_atomic_get_bit (os_atomic_p bits, int bitnum)
132 os_atomic_t *word_ptr = bits + (bitnum / OS_BITS_PER_ATOMIC_WORD);
133 os_atomic_t bit = (1 << (bitnum % OS_BITS_PER_ATOMIC_WORD));
134 os_atomic_t word = *word_ptr;
135 GUPCR_READ_FENCE();
136 return (word & bit) != 0;
139 void
140 __upc_atomic_set_bit (os_atomic_p bits, int bitnum)
142 os_atomic_t *word = bits + (bitnum / OS_BITS_PER_ATOMIC_WORD);
143 os_atomic_t bit = (1 << (bitnum % OS_BITS_PER_ATOMIC_WORD));
144 os_atomic_t old_val, new_val;
147 old_val = *word;
148 new_val = old_val | bit;
150 while (!__upc_atomic_cas (word, old_val, new_val));
153 os_heap_p
154 __upc_create_runtime_heap (size_t ARG_UNUSED (max_size),
155 const char **ARG_UNUSED (err_msg))
157 os_heap_p heap;
158 #ifdef __sgi__
159 /* Create the shared arena. */
160 (void) usconfig (CONF_INITSIZE, max_size);
161 heap = (os_heap_p) usinit (DEV_ZERO);
162 if (!heap)
163 { *err_msg = strerror(errno); return 0; }
164 #else
165 /* On platforms other than SGI/Irix we don't
166 need a heap, because mmap() will work well
167 for the limited number of data structures
168 allocated during runtime initialization. */
169 heap = (void *)-1;
170 #endif
171 return heap;
174 void *
175 __upc_runtime_alloc (size_t size, os_heap_p *ARG_UNUSED (heap),
176 const char **err_msg)
178 void *alloc;
179 #ifdef __sgi__
180 alloc = (void *) usmalloc (size, (usptr_t *)*heap);
181 if (!alloc)
182 { *err_msg = strerror(errno); return 0; }
183 #else
184 alloc = mmap ((void *) 0, size,
185 PROT_READ | PROT_WRITE,
186 MAP_SHARED | MAP_ANONYMOUS, 0, OFFSET_ZERO);
187 if (!alloc || alloc == MAP_ERROR)
188 { *err_msg = strerror(errno); return 0; }
189 #endif
190 return alloc;
193 void
194 __upc_init_lock (lock)
195 os_lock_p lock;
197 #ifdef __sgi__
199 upc_info_p u = __upc_info;
200 if (!u)
201 __upc_fatal ("UPC runtime not initialized");
202 *lock = (os_lock_t) usnewlock ((usptr_t *) u->runtime_heap);
203 if (!*lock)
204 { perror ("__upc_init_lock"); abort (); }
206 #else
207 *lock = 0;
208 #endif
211 void
212 __upc_acquire_lock (lock)
213 os_lock_p lock;
215 if (!lock)
216 __upc_fatal ("NULL shared pointer passed to UPC lock operation");
217 #ifdef __sgi__
219 int status;
220 status = ussetlock(*lock);
221 if (status == 0)
222 __upc_fatal ("upc_lock() could not acquire lock");
223 else if (status < 0)
224 { perror ("upc_acquire_lock"); abort (); }
226 #else
227 __upc_spin_until (__upc_atomic_cas ((os_atomic_p) lock, 0, 1));
228 #endif
229 GUPCR_FENCE();
233 __upc_try_acquire_lock (lock)
234 os_lock_p lock;
236 int status;
237 if (!lock)
238 __upc_fatal ("NULL shared pointer passed to UPC lock operation");
239 #ifdef __sgi__
240 status = uscsetlock(*lock, 0);
241 if (status < 0)
242 { perror ("upc_try_acquire_lock"); abort (); }
243 #else
244 status = __upc_atomic_cas ((os_atomic_p) lock, 0, 1);
245 #endif
246 if (status)
247 GUPCR_FENCE();
248 return status;
251 void
252 __upc_release_lock (lock)
253 os_lock_p lock;
255 if (!lock)
256 __upc_fatal ("NULL shared pointer passed to UPC lock operation");
257 GUPCR_FENCE();
258 #ifdef __sgi__
260 int status;
261 status = usunsetlock(*lock);
262 if (status > 0)
263 __upc_fatal ("upc_unlock() could not release lock");
264 else if (status < 0)
265 { perror ("upc_unlock"); abort (); }
267 #else
268 *((os_atomic_p) lock) = 0;
269 #endif
272 /* Given a "tag" (a relative filename ending in XXXXXX),
273 create a temporary file using the tag.
274 Return a file descriptor associated with the newly
275 created temporary file.
276 [see: http://www.linux.com/howtos/Secure-Programs-HOWTO/avoid-race.shtml] */
279 __upc_create_temp_file (const char *tag, char *tmp_fname,
280 const char **err_msg)
282 const char *tmpdir = NULL;
283 mode_t old_mode;
284 int fd;
285 if ((getuid () == geteuid ()) && (getgid () == getegid ()))
287 tmpdir = getenv ("TMPDIR");
288 if (!tmpdir)
289 tmpdir = getenv ("TMP");
291 if (!tmpdir)
292 tmpdir = "/tmp";
293 sprintf (tmp_fname, "%s/%s", tmpdir, tag);
294 /* Create file with restrictive permissions */
295 old_mode = umask (077);
296 fd = mkstemp (tmp_fname);
297 (void) umask (old_mode);
298 if (fd < 0)
299 *err_msg = "Couldn't open temporary file";
300 return fd;
303 /* Create a file that will be used as the backing store
304 for the UPC program's global shared memory. Return
305 a file descriptor that can subsequently be used
306 to mmap() the file. If an error is encountered,
307 fd will be set to -1, and err_msg will contain
308 a descriptive error message. */
310 __upc_create_global_mem_file (char *tmp_fname, const char **err_msg)
312 int fd;
313 char fname_template[30];
314 sprintf (fname_template, "upc_shmem.%d.XXXXXX", (int)getpid());
315 fd = __upc_create_temp_file (fname_template, tmp_fname, err_msg);
316 return fd;