[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