summaryrefslogtreecommitdiff
path: root/pthread_support.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2012-01-24 16:31:53 +0100
committerIvan Maidanski <ivmai@mail.ru>2012-01-26 17:47:21 +0100
commitcebfd92286f10f4d6f8faaa73a5e61896a42d3ad (patch)
tree3525211ce9e92b95b84ecdf22e8122890fca35d6 /pthread_support.c
parentd55ae3329cc612715b0506ed814601123a58d4e7 (diff)
Workaround some Linux/arm kernels bug to get correct GC_nprocs value
* pthread_support.c (STAT_READ, STAT_BUF_SIZE): Move the definition out of PLATFORM_ANDROID condition. * pthread_support.c (GC_get_nprocs_present): New static function obtaining number of avalable CPUs from "/sys/devices/system/cpu/present" (only Linux/arm excluding NaCl). * pthread_support.c (GC_thr_init): Invoke GC_get_nprocs_present (unless set from the environment variable) to workaround a bug in some Linux/arm kernels (including Android).
Diffstat (limited to 'pthread_support.c')
-rw-r--r--pthread_support.c56
1 files changed, 48 insertions, 8 deletions
diff --git a/pthread_support.c b/pthread_support.c
index 82db8ea..c78c0a6 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -703,6 +703,14 @@ STATIC void GC_remove_all_threads_but_me(void)
}
#endif /* IA64 */
+#ifndef STAT_READ
+ /* Also defined in os_dep.c. */
+# define STAT_BUF_SIZE 4096
+# define STAT_READ read
+ /* If read is wrapped, this may need to be redefined to call */
+ /* the real one. */
+#endif
+
#if defined(GC_LINUX_THREADS) && !defined(PLATFORM_ANDROID) && !defined(NACL)
/* Return the number of processors. */
STATIC int GC_get_nprocs(void)
@@ -710,13 +718,6 @@ STATIC void GC_remove_all_threads_but_me(void)
/* 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. */
-# ifndef STAT_READ
- /* Also defined in os_dep.c. */
-# define STAT_BUF_SIZE 4096
-# define STAT_READ read
-# endif
- /* If read is wrapped, this may need to be redefined to call */
- /* the real one. */
char stat_buf[STAT_BUF_SIZE];
int f;
int result, i, len;
@@ -746,6 +747,39 @@ STATIC void GC_remove_all_threads_but_me(void)
}
#endif /* GC_LINUX_THREADS && !PLATFORM_ANDROID && !NACL */
+#if defined(ARM32) && defined(GC_LINUX_THREADS) && !defined(NACL)
+ /* Some buggy Linux/arm kernels show only non-sleeping CPUs in */
+ /* /proc/stat (and /proc/cpuinfo), so another data system source is */
+ /* tried first. Result <= 0 on error. */
+ STATIC int GC_get_nprocs_present(void)
+ {
+ char stat_buf[16];
+ int f;
+ int len;
+
+ f = open("/sys/devices/system/cpu/present", O_RDONLY);
+ if (f < 0)
+ return -1; /* cannot open the file */
+
+ len = STAT_READ(f, stat_buf, sizeof(stat_buf));
+ close(f);
+
+ /* Recognized file format: "0\n" or "0-<max_cpu_id>\n" */
+ /* The file might probably contain a comma-separated list */
+ /* but we do not need to handle it (just silently ignore). */
+ if (len < 2 || stat_buf[0] != '0' || stat_buf[len - 1] != '\n') {
+ return 0; /* read error or unrecognized content */
+ } else if (len == 2) {
+ return 1; /* an uniprocessor */
+ } else if (stat_buf[1] != '-') {
+ return 0; /* unrecognized content */
+ }
+
+ stat_buf[len - 1] = '\0'; /* terminate the string */
+ return atoi(&stat_buf[2]) + 1; /* skip "0-" and parse max_cpu_num */
+ }
+#endif /* ARM32 && GC_LINUX_THREADS && !NACL */
+
/* We hold the GC lock. Wait until an in-progress GC has finished. */
/* Repeatedly RELEASES GC LOCK in order to wait. */
/* If wait_for_all is true, then we exit with the GC lock held and no */
@@ -940,7 +974,13 @@ GC_INNER void GC_thr_init(void)
GC_nprocs = -1;
if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
}
- if (GC_nprocs <= 0) {
+ if (GC_nprocs <= 0
+# if defined(ARM32) && defined(GC_LINUX_THREADS) && !defined(NACL)
+ && (GC_nprocs = GC_get_nprocs_present()) <= 1
+ /* Workaround for some Linux/arm kernels */
+# endif
+ )
+ {
# if defined(GC_HPUX_THREADS)
GC_nprocs = pthread_num_processors_np();
# elif defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \