Browse Source

Merge branch 'android' into bfgminer

Conflicts:
	Makefile.am
	configure.ac
Luke Dashjr 13 years ago
parent
commit
0b6311dfbb
7 changed files with 218 additions and 24 deletions
  1. 2 1
      Makefile.am
  2. 20 0
      compat.h
  3. 48 15
      configure.ac
  4. 11 0
      lib/stdint.in.h
  5. 36 0
      miner.c
  6. 6 8
      miner.h
  7. 95 0
      util.c

+ 2 - 1
Makefile.am

@@ -8,7 +8,7 @@ EXTRA_DIST	= example.conf m4/gnulib-cache.m4 linux-usb-bfgminer \
 
 SUBDIRS		= lib ccan
 
-INCLUDES	= $(PTHREAD_FLAGS) -fno-strict-aliasing
+INCLUDES	= -fno-strict-aliasing
 
 bin_PROGRAMS	= bfgminer
 
@@ -22,6 +22,7 @@ bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 bfgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @LIBUSB_CFLAGS@ @LIBCURL_CFLAGS@
 
 bfgminer_CPPFLAGS += @JANSSON_CFLAGS@
+bfgminer_CPPFLAGS += $(PTHREAD_FLAGS)
 bfgminer_CPPFLAGS += $(NCURSES_CPPFLAGS)
 
 # common sources

+ 20 - 0
compat.h

@@ -141,4 +141,24 @@ typedef long suseconds_t;
 #define PTH(thr) ((thr)->pth)
 #endif /* WIN32 */
 
+#ifndef HAVE_PTHREAD_CANCEL
+
+// Bionic (Android) is intentionally missing pthread_cancel, so it is implemented using pthread_kill (handled in util.c)
+#include <pthread.h>
+#include <signal.h>
+#define pthread_cancel(pth)  pthread_kill(pth, SIGTERM)
+#ifndef PTHREAD_CANCEL_ENABLE
+#define PTHREAD_CANCEL_ENABLE  0
+#define PTHREAD_CANCEL_DISABLE 1
+#endif
+#ifndef PTHREAD_CANCEL_DEFERRED
+#define PTHREAD_CANCEL_DEFERRED     0
+#define PTHREAD_CANCEL_ASYNCHRONOUS 1
+#endif
+#ifndef PTHREAD_CANCELED
+#define PTHREAD_CANCELED ((void*)-1)
+#endif
+
+#endif
+
 #endif /* __COMPAT_H__ */

+ 48 - 15
configure.ac

@@ -64,7 +64,6 @@ AC_FUNC_ALLOCA
 
 have_cygwin=false
 have_win32=false
-PTHREAD_FLAGS="-lpthread"
 DLOPEN_FLAGS="-ldl"
 WS2_LIBS=""
 MATH_LIBS="-lm"
@@ -88,7 +87,6 @@ case $target in
   *-*-mingw*)
     have_x86_64=false
     have_win32=true
-    PTHREAD_FLAGS=""
     DLOPEN_FLAGS=""
     WS2_LIBS="-lws2_32"
     AC_DEFINE([_WIN32_WINNT], [0x0501], "WinNT version for XP+ support")
@@ -99,11 +97,7 @@ case $target in
 	;;
   powerpc-*-darwin*)
     CFLAGS="$CFLAGS -faltivec"
-    PTHREAD_FLAGS=""
     ;;
-  *-*-darwin*)
-    PTHREAD_FLAGS=""
-	;;
 esac
 
 
@@ -153,11 +147,50 @@ else
 fi
 AM_CONDITIONAL([HAVE_OPENCL], [test x$opencl = xyes])
 
-AC_CHECK_LIB(pthread, pthread_create, [
-	true
-],
-        AC_MSG_ERROR([Could not find pthread library - please install libpthread]))
-PTHREAD_LIBS=-lpthread
+m4_define([BFG_PTHREAD_FLAG_CHECK],
+	AC_MSG_CHECKING([for $1])
+	for cflag in ' -pthread' ''; do
+		for lib in ' -lpthread' ''; do
+			CFLAGS="${save_CFLAGS}${cflag}"
+			LIBS="${save_LIBS}${lib}"
+			AC_LINK_IFELSE([
+				AC_LANG_PROGRAM([
+					#include <pthread.h>
+				], [
+					void *f = $1;
+				])
+			], [
+				found_pthread=true
+				PTHREAD_FLAGS="${cflag}"
+				PTHREAD_LIBS="${lib}"
+				if test "x${cflag}${lib}" = "x"; then
+					AC_MSG_RESULT([yes])
+				else
+					AC_MSG_RESULT([with${cflag}${lib}])
+				fi
+				$2
+				break 2
+			],[])
+		done
+	done
+)
+
+save_CFLAGS="${CFLAGS}"
+save_LIBS="${LIBS}"
+found_pthread=false
+BFG_PTHREAD_FLAG_CHECK([pthread_cancel],[
+	AC_DEFINE([HAVE_PTHREAD_CANCEL], [1], [Define if you have a native pthread_cancel])
+])
+if test "x${found_pthread}" = "xfalse"; then
+	AC_MSG_RESULT([no])
+	BFG_PTHREAD_FLAG_CHECK([pthread_create])
+	if test "x${found_pthread}" = "xfalse"; then
+		AC_MSG_RESULT([no])
+		AC_MSG_ERROR([Could not find pthread library - please install libpthread])
+	fi
+fi
+CFLAGS="${save_CFLAGS}"
+LIBS="${save_LIBS}"
 
 AC_CHECK_LIB(jansson, json_loads, [
 	JANSSON_LIBS=-ljansson
@@ -713,10 +746,10 @@ fi
 
 echo
 echo "Compilation............: make (or gmake)"
-echo "  CPPFLAGS.............:" $CPPFLAGS $NCURSES_CPPFLAGS
-echo "  CFLAGS...............:" $CFLAGS $LIBUSB_CFLAGS $JANSSON_CFLAGS
-echo "  LDFLAGS..............:" $LDFLAGS $PTHREAD_FLAGS
-echo "  LDADD................:" $LIBS $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $PTHREAD_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $LIBUSB_LIBS
+echo "  CPPFLAGS.............:" $CPPFLAGS $NCURSES_CPPFLAGS $PTHREAD_FLAGS
+echo "  CFLAGS...............:" $CFLAGS $LIBUSB_CFLAGS $JANSSON_CFLAGS $PTHREAD_FLAGS
+echo "  LDFLAGS..............:" $LDFLAGS $PTHREAD_FLAGS $PTHREAD_LIBS
+echo "  LDADD................:" $LIBS $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $LIBUSB_LIBS
 echo
 echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')"
 echo "  prefix...............: $prefix"

+ 11 - 0
lib/stdint.in.h

@@ -34,6 +34,16 @@
    <inttypes.h>.  */
 #define _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H
 
+/* On Android (Bionic libc), <sys/types.h> includes this file before
+   having defined 'time_t'.  Therefore in this case avoid including
+   other system header files; just include the system's <stdint.h>.
+   Ideally we should test __BIONIC__ here, but it is only defined after
+   <sys/cdefs.h> has been included; hence test __ANDROID__ instead.  */
+#if defined __ANDROID__ \
+    && defined _SYS_TYPES_H_ && !defined __need_size_t
+# @INCLUDE_NEXT@ @NEXT_STDINT_H@
+#else
+
 /* Get those types that are already defined in other system include
    files, so that we can "#define int8_t signed char" below without
    worrying about a later system include file containing a "typedef
@@ -589,4 +599,5 @@ typedef int _verify_intmax_size[sizeof (intmax_t) == sizeof (uintmax_t)
 #endif /* !defined __cplusplus || defined __STDC_CONSTANT_MACROS */
 
 #endif /* _@GUARD_PREFIX@_STDINT_H */
+#endif /* !(defined __ANDROID__ && ...) */
 #endif /* !defined _@GUARD_PREFIX@_STDINT_H && !defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H */

+ 36 - 0
miner.c

@@ -4637,6 +4637,10 @@ static void *stage_thread(void *userdata)
 	struct thr_info *mythr = userdata;
 	bool ok = true;
 
+#ifndef HAVE_PTHREAD_CANCEL
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+#endif
+
 	RenameThread("stage");
 
 	while (ok) {
@@ -6894,6 +6898,10 @@ static void *longpoll_thread(void *userdata)
 	char *lp_url;
 	int rolltime;
 
+#ifndef HAVE_PTHREAD_CANCEL
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+#endif
+
 	RenameThread("longpoll");
 
 	curl = curl_easy_init();
@@ -7078,6 +7086,10 @@ static void *watchpool_thread(void __maybe_unused *userdata)
 {
 	int intervals = 0;
 
+#ifndef HAVE_PTHREAD_CANCEL
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+#endif
+
 	RenameThread("watchpool");
 
 	while (42) {
@@ -7157,6 +7169,10 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 	const unsigned int interval = WATCHDOG_INTERVAL;
 	struct timeval zero_tv;
 
+#ifndef HAVE_PTHREAD_CANCEL
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+#endif
+
 	RenameThread("watchdog");
 
 	memset(&zero_tv, 0, sizeof(struct timeval));
@@ -7790,6 +7806,11 @@ static bool my_blkmaker_sha256_callback(void *digest, const void *buffer, size_t
 	return true;
 }
 
+#ifndef HAVE_PTHREAD_CANCEL
+extern void setup_pthread_cancel_workaround();
+extern struct sigaction pcwm_orig_term_handler;
+#endif
+
 int main(int argc, char *argv[])
 {
 	bool pools_active = false;
@@ -7802,6 +7823,10 @@ int main(int argc, char *argv[])
 
 	blkmk_sha256_impl = my_blkmaker_sha256_callback;
 
+#ifndef HAVE_PTHREAD_CANCEL
+	setup_pthread_cancel_workaround();
+#endif
+
 	/* This dangerous functions tramples random dynamically allocated
 	 * variables so do it before anything at all */
 	if (unlikely(curl_global_init(CURL_GLOBAL_ALL)))
@@ -7850,7 +7875,13 @@ int main(int argc, char *argv[])
 	handler.sa_handler = &sighandler;
 	handler.sa_flags = 0;
 	sigemptyset(&handler.sa_mask);
+#ifdef HAVE_PTHREAD_CANCEL
 	sigaction(SIGTERM, &handler, &termhandler);
+#else
+	// Need to let pthread_cancel emulation handle SIGTERM first
+	termhandler = pcwm_orig_term_handler;
+	pcwm_orig_term_handler = handler;
+#endif
 	sigaction(SIGINT, &handler, &inthandler);
 #ifndef WIN32
 	signal(SIGPIPE, SIG_IGN);
@@ -7913,6 +7944,11 @@ int main(int argc, char *argv[])
 	if (!config_loaded)
 		load_default_config();
 
+#ifndef HAVE_PTHREAD_CANCEL
+	// Can't do this any earlier, or config isn't loaded
+	applog(LOG_DEBUG, "pthread_cancel workaround in use");
+#endif
+
 	if (opt_benchmark) {
 		struct pool *pool;
 

+ 6 - 8
miner.h

@@ -127,26 +127,24 @@ static inline int fsync (int fd)
  * also won't exist */
 #ifndef htobe32
 # ifndef WORDS_BIGENDIAN
-#  define le32toh(x) (x)
-#  define le64toh(x) (x)
 #  define htole16(x) (x)
 #  define htole32(x) (x)
 #  define htole64(x) (x)
-#  define be32toh(x) bswap_32(x)
-#  define be64toh(x) bswap_64(x)
 #  define htobe32(x) bswap_32(x)
 #  define htobe64(x) bswap_64(x)
 # else
-#  define le32toh(x) bswap_32(x)
-#  define le64toh(x) bswap_64(x)
 #  define htole16(x) bswap_16(x)
 #  define htole32(x) bswap_32(x)
 #  define htole64(x) bswap_64(x)
-#  define be32toh(x) (x)
-#  define be64toh(x) (x)
 #  define htobe32(x) (x)
 #  define htobe64(x) (x)
+# endif
 #endif
+#ifndef be32toh
+# define le32toh(x) htole32(x)
+# define le64toh(x) htole64(x)
+# define be32toh(x) htobe32(x)
+# define be64toh(x) htobe64(x)
 #endif
 
 #ifndef max

+ 95 - 0
util.c

@@ -942,6 +942,101 @@ void thr_info_cancel(struct thr_info *thr)
 	}
 }
 
+#ifndef HAVE_PTHREAD_CANCEL
+
+// Bionic (Android) is intentionally missing pthread_cancel, so it is implemented using pthread_kill
+
+enum pthread_cancel_workaround_mode {
+	PCWM_DEFAULT   = 0,
+	PCWM_TERMINATE = 1,
+	PCWM_ASYNC     = 2,
+	PCWM_DISABLED  = 4,
+	PCWM_CANCELLED = 8,
+};
+
+static pthread_key_t key_pcwm;
+struct sigaction pcwm_orig_term_handler;
+
+static
+void do_pthread_cancel_exit(int flags)
+{
+	if (!(flags & PCWM_ASYNC))
+		// NOTE: Logging disables cancel while mutex held, so this is safe
+		applog(LOG_WARNING, "pthread_cancel workaround: Cannot defer cancellation, terminating thread NOW");
+	pthread_exit(PTHREAD_CANCELED);
+}
+
+static
+void sighandler_pthread_cancel(int sig)
+{
+	int flags = (int)pthread_getspecific(key_pcwm);
+	if (flags & PCWM_TERMINATE)  // Main thread
+	{
+		// Restore original handler and call it
+		if (sigaction(sig, &pcwm_orig_term_handler, NULL))
+			quit(1, "pthread_cancel workaround: Failed to restore original handler");
+		raise(SIGTERM);
+		quit(1, "pthread_cancel workaround: Original handler returned");
+	}
+	if (flags & PCWM_CANCELLED)  // Already pending cancel
+		return;
+	if (flags & PCWM_DISABLED)
+	{
+		flags |= PCWM_CANCELLED;
+		if (pthread_setspecific(key_pcwm, (void*)flags))
+			quit(1, "pthread_cancel workaround: pthread_setspecific failed (setting PCWM_CANCELLED)");
+		return;
+	}
+	do_pthread_cancel_exit(flags);
+}
+
+int pthread_setcancelstate(int state, int *oldstate)
+{
+	int flags = (int)pthread_getspecific(key_pcwm);
+	if (oldstate)
+		*oldstate = (flags & PCWM_DISABLED) ? PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE;
+	if (state == PTHREAD_CANCEL_DISABLE)
+		flags |= PCWM_DISABLED;
+	else
+	{
+		if (flags & PCWM_CANCELLED)
+			do_pthread_cancel_exit(flags);
+		flags &= ~PCWM_DISABLED;
+	}
+	if (pthread_setspecific(key_pcwm, (void*)flags))
+		return -1;
+	return 0;
+}
+
+int pthread_setcanceltype(int type, int *oldtype)
+{
+	int flags = (int)pthread_getspecific(key_pcwm);
+	if (oldtype)
+		*oldtype = (flags & PCWM_ASYNC) ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED;
+	if (type == PTHREAD_CANCEL_ASYNCHRONOUS)
+		flags |= PCWM_ASYNC;
+	else
+		flags &= ~PCWM_ASYNC;
+	if (pthread_setspecific(key_pcwm, (void*)flags))
+		return -1;
+	return 0;
+}
+
+void setup_pthread_cancel_workaround()
+{
+	if (pthread_key_create(&key_pcwm, NULL))
+		quit(1, "pthread_cancel workaround: pthread_key_create failed");
+	if (pthread_setspecific(key_pcwm, (void*)PCWM_TERMINATE))
+		quit(1, "pthread_cancel workaround: pthread_setspecific failed");
+	struct sigaction new_sigact = {
+		.sa_handler = sighandler_pthread_cancel,
+	};
+	if (sigaction(SIGTERM, &new_sigact, &pcwm_orig_term_handler))
+		quit(1, "pthread_cancel workaround: Failed to install SIGTERM handler");
+}
+
+#endif
+
 /* Provide a ms based sleep that uses nanosleep to avoid poor usleep accuracy
  * on SMP machines */
 void nmsleep(unsigned int msecs)