Commit b59c33800b75d0c84842dcc2f369aaecbb8db227

ckolivas 2013-06-06T13:08:00

Implement cgminer specific cgsem semaphores to imitate unnamed semaphore behaviour on osx which does not support them.

diff --git a/cgminer.c b/cgminer.c
index 63e0dc2..5f02d4e 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -150,7 +150,7 @@ char *opt_avalon_options = NULL;
 char *opt_usb_select = NULL;
 int opt_usbdump = -1;
 bool opt_usb_list_all;
-sem_t usb_resource_sem;
+cgsem_t usb_resource_sem;
 #endif
 
 char *opt_kernel_path;
@@ -7442,8 +7442,7 @@ int main(int argc, char *argv[])
 
 	// before device detection
 	if (!opt_scrypt) {
-		if (sem_init(&usb_resource_sem, 0, 0))
-			quit(1, "Failed to sem_init usb_resource_sem");
+		cgsem_init(&usb_resource_sem);
 		usbres_thr_id = 1;
 		thr = &control_thr[usbres_thr_id];
 		if (thr_info_create(thr, NULL, usb_resource_thread, thr))
diff --git a/driver-avalon.c b/driver-avalon.c
index 789fc53..ea112ca 100644
--- a/driver-avalon.c
+++ b/driver-avalon.c
@@ -769,8 +769,8 @@ static void *avalon_get_results(void *userdata)
 
 		if (unlikely(info->reset)) {
 			/* Tell the write thread it can start the reset */
-			sem_post(&info->write_sem);
-			sem_wait(&info->read_sem);
+			cgsem_post(&info->write_sem);
+			cgsem_wait(&info->read_sem);
 
 			/* Discard anything in the buffer */
 			offset = 0;
@@ -820,9 +820,9 @@ static void *avalon_send_tasks(void *userdata)
 		if (unlikely(info->reset)) {
 			/* Wait till read thread tells us it's received the
 			 * reset message */
-			sem_wait(&info->write_sem);
+			cgsem_wait(&info->write_sem);
 			avalon_running_reset(avalon, info);
-			sem_post(&info->read_sem);
+			cgsem_post(&info->read_sem);
 		}
 
 		mutex_lock(&info->qlock);
@@ -890,10 +890,8 @@ static bool avalon_prepare(struct thr_info *thr)
 	mutex_init(&info->qlock);
 	if (unlikely(pthread_cond_init(&info->qcond, NULL)))
 		quit(1, "Failed to pthread_cond_init avalon qcond");
-	if (unlikely(sem_init(&info->read_sem, 0, 0)))
-		quit(1, "Failed to sem_init avalon read_sem");
-	if (unlikely(sem_init(&info->write_sem, 0, 0)))
-		quit(1, "Failed to sem_init avalon write_sem");
+	cgsem_init(&info->read_sem);
+	cgsem_init(&info->write_sem);
 
 	if (pthread_create(&info->read_thr, NULL, avalon_get_results, (void *)avalon))
 		quit(1, "Failed to create avalon read_thr");
@@ -918,6 +916,9 @@ static void do_avalon_close(struct thr_info *thr)
 	avalon_running_reset(avalon, info);
 
 	info->no_matching_work = 0;
+
+	cgsem_destroy(&info->read_sem);
+	cgsem_destroy(&info->write_sem);
 }
 
 static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg)
diff --git a/driver-avalon.h b/driver-avalon.h
index 6f101c9..b5ff3e5 100644
--- a/driver-avalon.h
+++ b/driver-avalon.h
@@ -13,7 +13,7 @@
 
 #ifdef USE_AVALON
 
-#include <semaphore.h>
+#include "util.h"
 
 #define AVALON_RESET_FAULT_DECISECONDS 1
 #define AVALON_MINER_THREADS 1
@@ -110,8 +110,8 @@ struct avalon_info {
 	pthread_mutex_t lock;
 	pthread_mutex_t qlock;
 	pthread_cond_t qcond;
-	sem_t read_sem;
-	sem_t write_sem;
+	cgsem_t read_sem;
+	cgsem_t write_sem;
 	int nonces;
 
 	bool idle;
diff --git a/miner.h b/miner.h
index 725c1ab..752de5e 100644
--- a/miner.h
+++ b/miner.h
@@ -855,7 +855,7 @@ extern char *opt_avalon_options;
 extern char *opt_usb_select;
 extern int opt_usbdump;
 extern bool opt_usb_list_all;
-extern sem_t usb_resource_sem;
+extern cgsem_t usb_resource_sem;
 #endif
 #ifdef USE_BITFORCE
 extern bool opt_bfl_noncerange;
diff --git a/usbutils.c b/usbutils.c
index c793b9a..323bd7c 100644
--- a/usbutils.c
+++ b/usbutils.c
@@ -1225,7 +1225,7 @@ static bool cgminer_usb_lock_bd(struct device_drv *drv, uint8_t bus_number, uint
 	res_work_head = res_work;
 	mutex_unlock(&cgusbres_lock);
 
-	sem_post(&usb_resource_sem);
+	cgsem_post(&usb_resource_sem);
 
 	// TODO: add a timeout fail - restart the resource thread?
 	while (true) {
@@ -1284,7 +1284,7 @@ static void cgminer_usb_unlock_bd(struct device_drv *drv, uint8_t bus_number, ui
 	res_work_head = res_work;
 	mutex_unlock(&cgusbres_lock);
 
-	sem_post(&usb_resource_sem);
+	cgsem_post(&usb_resource_sem);
 
 	return;
 }
@@ -2610,6 +2610,8 @@ void usb_cleanup()
 		}
 		mutex_unlock(&cgusbres_lock);
 	}
+
+	cgsem_destroy(&usb_resource_sem);
 }
 
 void usb_initialise()
@@ -3115,7 +3117,7 @@ void *usb_resource_thread(void __maybe_unused *userdata)
 
 	while (42) {
 		/* Wait to be told we have work to do */
-		sem_wait(&usb_resource_sem);
+		cgsem_wait(&usb_resource_sem);
 
 		mutex_lock(&cgusbres_lock);
 		while (res_work_head)
diff --git a/util.c b/util.c
index 1433477..f91763a 100644
--- a/util.c
+++ b/util.c
@@ -1870,3 +1870,74 @@ void RenameThread(const char* name)
 #endif
 }
 
+/* cgminer specific wrappers for true unnamed semaphore usage on platforms
+ * that support them and for apple which does not. We use a single byte across
+ * a pipe to emulate semaphore behaviour there. */
+#ifdef __APPLE__
+void cgsem_init(cgsem_t *cgsem)
+{
+	int flags, fd, i;
+
+	if (pipe(cgsem->pipefd) == -1)
+		quit(1, "Failed pipe in cgsem_init");
+
+	/* Make the pipes FD_CLOEXEC to allow them to close should we call
+	 * execv on restart. */
+	for (i = 0; i < 2; i++) {
+		fd = cgsem->pipefd[i];
+		flags = fcntl(fd, F_GETFD, 0);
+		flags |= FD_CLOEXEC;
+		if (fcntl(fd, F_SETFD, flags) == -1)
+			quit(1, "Failed to fcntl in cgsem_init");
+	}
+}
+
+void cgsem_post(cgsem_t *cgsem)
+{
+	const char buf = 1;
+	int ret;
+
+	ret = write(cgsem->pipefd[1], &buf, 1);
+	if (ret == 0)
+		quit(1, "Failed to write in cgsem_post");
+}
+
+void cgsem_wait(cgsem_t *cgsem)
+{
+	char buf;
+	int ret;
+
+	ret = read(cgsem->pipefd[0], &buf, 1);
+	if (ret == 0)
+		quit(1, "Failed to read in cgsem_wait");
+}
+
+void cgsem_destroy(cgsem_t *cgsem)
+{
+	close(cgsem->pipefd[1]);
+	close(cgsem->pipefd[0]);
+}
+#else
+void cgsem_init(cgsem_t *cgsem)
+{
+	if (sem_init(cgsem, 0, 0))
+		quit(1, "Failed to sem_init in cgsem_init");
+}
+
+void cgsem_post(cgsem_t *cgsem)
+{
+	if (unlikely(sem_post(cgsem)))
+		quit(1, "Failed to sem_post in cgsem_post");
+}
+
+void cgsem_wait(cgsem_t *cgsem)
+{
+	if (unlikely(sem_wait(cgsem)))
+		quit(1, "Failed to sem_wait in cgsem_wait");
+}
+
+void cgsem_destroy(cgsem_t *cgsem)
+{
+	sem_destroy(cgsem);
+}
+#endif
diff --git a/util.h b/util.h
index 5facbc5..8f82b87 100644
--- a/util.h
+++ b/util.h
@@ -1,6 +1,8 @@
 #ifndef __UTIL_H__
 #define __UTIL_H__
 
+#include <semaphore.h>
+
 #if defined(unix) || defined(__APPLE__)
 	#include <errno.h>
 	#include <sys/socket.h>
@@ -50,6 +52,18 @@
 #define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr))
 #endif
 
+/* cgminer specific unnamed semaphore implementations to cope with osx not
+ * implementing them. */
+#ifdef __APPLE__
+struct cgsem {
+	int pipefd[2];
+};
+
+typedef struct cgsem cgsem_t;
+#else
+typedef sem_t cgsem_t;
+#endif
+
 struct thr_info;
 struct pool;
 enum dev_reason;
@@ -80,6 +94,10 @@ void dev_error(struct cgpu_info *dev, enum dev_reason reason);
 void *realloc_strcat(char *ptr, char *s);
 void *str_text(char *ptr);
 void RenameThread(const char* name);
+void cgsem_init(cgsem_t *cgsem);
+void cgsem_post(cgsem_t *cgsem);
+void cgsem_wait(cgsem_t *cgsem);
+void cgsem_destroy(cgsem_t *cgsem);
 
 /* Align a size_t to 4 byte boundaries for fussy arches */
 static inline void align_len(size_t *len)