[PATCH] lib: acpica: fix semaphore counting by waiting for threads to complete

Colin King colin.king at canonical.com
Thu Jul 19 08:44:18 UTC 2012


From: Colin Ian King <colin.king at canonical.com>

When executing Notify() handlers ACPICA creates separate threads which
we need to wait to complete before we do any semaphore usage accounting.
This is because these threads can themselves use internal or AML semaphores
which will be in an unknown state if we do the start doing semaphore
usage accounted before we wait for them to terminate.  This patch adds
in an array to keep track of threads created by AcpiOsExecute and also
a pthread join on these running threads before we start counting any
used semaphores.

Note that we have to deprecate the ACPICA verison of AcpiOsExecute and
re-implement this in fwts to allow us to do the thread creation tracking.

Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 src/acpica/Makefile.am   |    3 +-
 src/acpica/fwts_acpica.c |  106 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/src/acpica/Makefile.am b/src/acpica/Makefile.am
index e2213d5..6b3bfa5 100644
--- a/src/acpica/Makefile.am
+++ b/src/acpica/Makefile.am
@@ -24,7 +24,8 @@ osunixxf_munged.c: $(ACPICA_OSL)/osunixxf.c
 	sed 's/^AcpiOsDeleteSemaphore/__AcpiOsDeleteSemaphore/' | \
 	sed 's/^AcpiOsVprintf/__AcpiOsVprintf/' | \
 	sed 's/^AcpiOsSignal/__AcpiOsSignal/' | \
-	sed 's/^AcpiOsSleep/__AcpiOsSleep/' \
+	sed 's/^AcpiOsSleep/__AcpiOsSleep/' | \
+	sed 's/^AcpiOsExecute/__AcpiOsExecute/' \
 	> osunixxf_munged.c
 
 #
diff --git a/src/acpica/fwts_acpica.c b/src/acpica/fwts_acpica.c
index cf9a4fe..08b012d 100644
--- a/src/acpica/fwts_acpica.c
+++ b/src/acpica/fwts_acpica.c
@@ -32,6 +32,7 @@
 #include <pthread.h>
 
 static pthread_mutex_t mutex_lock_count;
+static pthread_mutex_t mutex_thread_info;
 
 #include "fwts.h"
 
@@ -54,11 +55,15 @@ static pthread_mutex_t mutex_lock_count;
 #define MAX_SEMAPHORES		(1009)
 #define HASH_FULL		(0xffffffff)
 
+#define MAX_THREADS		(128)
+
 typedef struct {
 	sem_t		*sem;	/* Semaphore handle */
 	int		count;	/* count > 0 if acquired */
 } sem_hash;
 
+typedef void * (*PTHREAD_CALLBACK)(void *);
+
 BOOLEAN AcpiGbl_IgnoreErrors = FALSE;
 UINT8   AcpiGbl_RegionFillValue = 0;
 
@@ -70,6 +75,16 @@ static sem_hash			sem_hash_table[MAX_SEMAPHORES];
 static ACPI_TABLE_DESC		Tables[ACPI_MAX_INIT_TABLES];
 
 /*
+ *  Used to account for threads used by AcpiOsExecute
+ */
+typedef struct {
+	bool		used;	/* true if the thread accounting info in use by a thread */
+	pthread_t	thread;	/* thread info */
+} fwts_thread;
+
+static fwts_thread	threads[MAX_THREADS];
+
+/*
  *  Static copies of ACPI tables used by ACPICA execution engine
  */
 static ACPI_TABLE_XSDT 		*fwts_acpica_XSDT;
@@ -133,6 +148,27 @@ void fwts_acpica_sem_count_get(int *acquired, int *released)
 	*acquired = 0;
 	*released = 0;
 
+	/* Wait for any pending threads to complete */
+
+	for (i = 0; i < MAX_THREADS; i++) {
+		pthread_mutex_lock(&mutex_thread_info);
+		if (threads[i].used) {
+			pthread_mutex_unlock(&mutex_thread_info);
+
+			/* Wait for thread to complete */
+			pthread_join(threads[i].thread, NULL);
+
+			pthread_mutex_lock(&mutex_thread_info);
+			threads[i].used = false;
+			pthread_mutex_unlock(&mutex_thread_info);
+		}
+		pthread_mutex_unlock(&mutex_thread_info);
+	}
+
+	/*
+	 * All threads (such as Notify() calls now complete, so
+	 * we can now do the semaphore accounting calculations
+	 */
 	for (i=0;i<MAX_SEMAPHORES;i++) {
 		if (sem_hash_table[i].sem != NULL) {
 			(*acquired)++;
@@ -624,6 +660,74 @@ ACPI_STATUS AcpiOsReadPort(ACPI_IO_ADDRESS addr, UINT32 *value, UINT32 width)
 	return AE_OK;
 }
 
+typedef struct {
+	PTHREAD_CALLBACK	func;
+	void *			context;
+	int			thread_index;
+} fwts_func_wrapper_context;
+
+/*
+ *  fwts_pthread_func_wrapper()
+ *	wrap the AcpiOsExecute function so we can mark the thread
+ *	accounting free once the function has completed.
+ */
+void *fwts_pthread_func_wrapper(fwts_func_wrapper_context *ctx)
+{
+	void *ret;
+
+	ret = ctx->func(ctx->context);
+
+	pthread_mutex_lock(&mutex_thread_info);
+	threads[ctx->thread_index].used = false;
+	pthread_mutex_unlock(&mutex_thread_info);
+
+	free(ctx);
+
+	return ret;
+}
+
+ACPI_STATUS AcpiOsExecute(
+	ACPI_EXECUTE_TYPE       type,
+	ACPI_OSD_EXEC_CALLBACK  function,
+	void                    *func_context)
+{
+	int	ret;
+	int 	i;
+
+	pthread_mutex_lock(&mutex_thread_info);
+
+	/* Find a free slot to do per-thread join tracking */
+	for (i = 0; i < MAX_THREADS; i++) {
+		if (!threads[i].used) {
+			fwts_func_wrapper_context *ctx;
+
+			/* We need some context to pass through to the thread wrapper */
+			if ((ctx = malloc(sizeof(fwts_func_wrapper_context))) == NULL) {
+				pthread_mutex_unlock(&mutex_thread_info);
+				return AE_NO_MEMORY;
+			}
+
+			ctx->func = (PTHREAD_CALLBACK)function;
+			ctx->context = func_context;
+			ctx->thread_index = i;
+			threads[i].used = true;
+
+			ret = pthread_create(&threads[i].thread, NULL,
+				(PTHREAD_CALLBACK)fwts_pthread_func_wrapper, ctx);
+			pthread_mutex_unlock(&mutex_thread_info);
+
+			if (ret)
+				return AE_ERROR;
+
+			return AE_OK;
+		}
+	}
+
+	/* No free slots, failed! */
+	pthread_mutex_unlock(&mutex_thread_info);
+	return AE_NO_MEMORY;
+}
+
 /*
  *  AcpiOsReadPciConfiguration()
  *	Override ACPICA AcpiOsReadPciConfiguration to fake PCI reads
@@ -802,6 +906,7 @@ int fwts_acpica_init(fwts_framework *fw)
 		return FWTS_ERROR;
 
 	pthread_mutex_init(&mutex_lock_count, NULL);
+	pthread_mutex_init(&mutex_thread_info, NULL);
 
 	fwts_acpica_fw = fw;
 
@@ -990,6 +1095,7 @@ int fwts_acpica_deinit(void)
 
 	AcpiTerminate();
 	pthread_mutex_destroy(&mutex_lock_count);
+	pthread_mutex_destroy(&mutex_thread_info);
 
 	FWTS_ACPICA_FREE(fwts_acpica_XSDT);
 	FWTS_ACPICA_FREE(fwts_acpica_RSDT);
-- 
1.7.10.4




More information about the fwts-devel mailing list