* None of this is safe with dlclose and incremental collection.
* But then not much of anything is safe in the presence of dlclose.
*/
-#if defined(__linux__) && !defined(_GNU_SOURCE)
+#if (defined(__linux__) || defined(__native_client__)) && !defined(_GNU_SOURCE)
/* Can't test LINUX, since this must be define before other includes */
# define _GNU_SOURCE
#endif
#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
!defined(MSWIN32) && !defined(MSWINCE) && \
!(defined(ALPHA) && defined(OSF1)) && \
- !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
+ !defined(HPUX) && !((defined(LINUX) || defined(NACL)) && defined(__ELF__)) && \
!defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
!(defined(FREEBSD) && defined(__ELF__)) && \
!(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) && \
# define ELFSIZE ARCH_ELFSIZE
#endif
-#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
+#if (defined(LINUX) || defined(NACL)) && defined(__ELF__) || defined(SCO_ELF) || \
(defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(OPENBSD) && defined(__ELF__)) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
# endif /* !USE_PROC ... */
# endif /* SUNOS */
-#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
+#if (defined(LINUX) || defined(NACL)) && defined(__ELF__) || defined(SCO_ELF) || \
(defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(OPENBSD) && defined(__ELF__)) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
/* For glibc 2.2.4+. Unfortunately, it doesn't work for older */
/* versions. Thanks to Jakub Jelinek for most of the code. */
-# if defined(LINUX) /* Are others OK here, too? */ \
+# if (defined(LINUX) || defined(NACL)) /* Are others OK here, too? */ \
&& (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
/* Determine the machine type: */
# if defined(__native_client__)
# define NACL
-# define I386
-# define mach_type_known
+# if !defined(__portable_native_client__)
+# define I386
+# define mach_type_known
+# else
+ /* Here we will rely upon arch-specific defines. */
+# endif
# endif
# if defined(__arm__) || defined(__thumb__)
# define ARM32
# endif
# endif
+
+# ifdef NACL
+# define OS_TYPE "NACL"
+# if defined(__GLIBC__)
+# define DYNAMIC_LOADING
+# endif
+# define DATASTART ((ptr_t)0x10020000)
+ extern int _end[];
+# define DATAEND (_end)
+# ifdef STACK_GRAN
+# undef STACK_GRAN
+# endif /* STACK_GRAN */
+# define STACK_GRAN 0x10000
+# define HEURISTIC1
+# define USE_MMAP
+# define USE_MUNMAP
+# define USE_MMAP_ANON
+# ifdef USE_MMAP_FIXED
+# undef USE_MMAP_FIXED
+# endif
+# define GETPAGESIZE() 65536
+# define MAX_NACL_GC_THREADS 1024
+# endif
+
# ifdef VAX
# define MACH_TYPE "VAX"
# define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */
# define HEAP_START DATAEND
# endif /* USE_MMAP */
# endif /* DGUX */
-# ifdef NACL
-# define OS_TYPE "NACL"
- extern int etext[];
-//# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
-# define DATASTART ((ptr_t)0x10000000)
- extern int _end[];
-# define DATAEND (_end)
-# ifdef STACK_GRAN
-# undef STACK_GRAN
-# endif /* STACK_GRAN */
-# define STACK_GRAN 0x10000
-# define HEURISTIC1
-# ifdef USE_MMAP
-# undef USE_MMAP
-# endif
-# ifdef USE_MUNMAP
-# undef USE_MUNMAP
-# endif
-# ifdef USE_MMAP_ANON
-# undef USE_MMAP_ANON
-# endif
-# ifdef USE_MMAP_FIXED
-# undef USE_MMAP_FIXED
-# endif
-# define GETPAGESIZE() 65536
-# define MAX_NACL_GC_THREADS 1024
-# endif
# ifdef LINUX
# ifndef __GNUC__
/* The Intel compiler doesn't like inline assembly */
buf[1024] = 0x15;
(void) sprintf(buf, format, a, b, c, d, e, f);
if (buf[1024] != 0x15) ABORT("GC_printf clobbered stack");
+#ifdef NACL
+ WRITE(GC_stdout, buf, strlen(buf));
+#else
if (WRITE(GC_stdout, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
+#endif
}
void GC_err_printf(format, a, b, c, d, e, f)
buf[1024] = 0x15;
(void) sprintf(buf, format, a, b, c, d, e, f);
if (buf[1024] != 0x15) ABORT("GC_err_printf clobbered stack");
+#ifdef NACL
+ WRITE(GC_stderr, buf, strlen(buf));
+#else
if (WRITE(GC_stderr, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
+#endif
}
void GC_err_puts(s)
GC_CONST char *s;
{
+#ifdef NACL
+ WRITE(GC_stderr, s, strlen(s));
+#else
if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
+#endif
}
#if defined(LINUX) && !defined(SMALL_CONFIG)
#endif
#ifdef NACL
-int nacl_park_threads_now = 0;
+volatile int __nacl_thread_suspension_needed = 0;
pthread_t nacl_thread_parker = -1;
volatile int nacl_thread_parked[MAX_NACL_GC_THREADS];
GC_printf1("pthread_stop_world: num_threads %d\n", nacl_num_gc_threads - 1);
#endif
nacl_thread_parker = pthread_self();
- nacl_park_threads_now = 1;
+ __nacl_thread_suspension_needed = 1;
while (1) {
#define NACL_PARK_WAIT_NANOSECONDS 100000
}
}
+void __nacl_suspend_thread_if_needed();
+
void nacl_post_syscall_hook()
{
/* Calling __nacl_suspend_thread_if_needed() right away should guarantee we don't mutate the GC set. */
}
void __nacl_suspend_thread_if_needed() {
- if (nacl_park_threads_now) {
+ if (__nacl_thread_suspension_needed) {
pthread_t self = pthread_self();
int local_dummy = 0;
/* Don't try to park the thread parker. */
nacl_gc_thread_self->stop_info.stack_ptr = (ptr_t)(&local_dummy);
}
nacl_thread_parked[nacl_thread_idx] = 1;
- while (nacl_park_threads_now)
+ while (__nacl_thread_suspension_needed)
; /* spin */
nacl_thread_parked[nacl_thread_idx] = 0;
# if DEBUG_THREADS
GC_printf0("World starting\n");
# endif
- nacl_park_threads_now = 0;
+ __nacl_thread_suspension_needed = 0;
if (GC_notify_event)
GC_notify_event (GC_EVENT_POST_START_WORLD);
#endif /* NACL */
extern void nacl_post_syscall_hook();
extern void nacl_register_gc_hooks(void (*pre)(), void (*post)());
+#include <stdio.h>
+
+struct nacl_irt_blockhook {
+ int (*register_block_hooks)(void (*pre)(void), void (*post)(void));
+};
+
+extern size_t nacl_interface_query(const char *interface_ident,
+ void *table, size_t tablesize);
+
void nacl_initialize_gc_thread()
{
int i;
- nacl_register_gc_hooks(nacl_pre_syscall_hook, nacl_post_syscall_hook);
+ static struct nacl_irt_blockhook gc_hook;
+
pthread_mutex_lock(&nacl_thread_alloc_lock);
if (!nacl_thread_parking_inited)
{
nacl_thread_used[i] = 0;
nacl_thread_parked[i] = 0;
}
+ // TODO: replace with public 'register hook' function when
+ // available from glibc
+ nacl_interface_query("nacl-irt-blockhook-0.1", &gc_hook, sizeof(gc_hook));
+ gc_hook.register_block_hooks(nacl_pre_syscall_hook, nacl_post_syscall_hook);
nacl_thread_parking_inited = 1;
}
GC_ASSERT(nacl_num_gc_threads <= MAX_NACL_GC_THREADS);
/* Return the number of processors, or i<= 0 if it can't be determined. */
int GC_get_nprocs()
{
+#ifndef NACL
/* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
/* appears to be buggy in many cases. */
/* We look for lines "cpu<n>" in /proc/stat. */
}
close(f);
return result;
+#else /* NACL */
+ return sysconf(_SC_NPROCESSORS_ONLN);
+#endif
}
#endif /* GC_LINUX_THREADS */
}
#ifdef NACL
-/* Native Client doesn't support pthread cleanup functions, */
-/* so wrap pthread_exit and manually cleanup the thread. */
+/* TODO: remove, NaCl glibc now supports pthread cleanup functions. */
void
WRAP_FUNC(pthread_exit)(void *status)
{
- GC_thread_exit_proc(0);
REAL_FUNC(pthread_exit)(status);
}
#endif