OSDN Git Service

Start of threading library
authorSharvil Nanavati <sharvil@google.com>
Thu, 8 May 2014 05:09:12 +0000 (22:09 -0700)
committerSharvil Nanavati <sharvil@google.com>
Wed, 9 Jul 2014 16:21:19 +0000 (16:21 +0000)
So far it's a thin shim around pthreads which allows setting thread
name and querying tids from any thread.

Change-Id: Id156f662778806a54a8a302be424ee051fac4710

osi/Android.mk
osi/include/thread.h [new file with mode: 0644]
osi/src/thread.c [new file with mode: 0644]
osi/test/thread_test.cpp [new file with mode: 0644]

index 646209c..5d2f5e3 100644 (file)
@@ -10,7 +10,8 @@ LOCAL_SRC_FILES := \
     ./src/fixed_queue.c \
     ./src/list.c \
     ./src/reactor.c \
-    ./src/semaphore.c
+    ./src/semaphore.c \
+    ./src/thread.c
 
 LOCAL_CFLAGS := -std=c99 -Wall -Werror
 LOCAL_MODULE := libosi
@@ -30,7 +31,8 @@ LOCAL_C_INCLUDES := \
 LOCAL_SRC_FILES := \
     ./test/config_test.cpp \
     ./test/list_test.cpp \
-    ./test/reactor_test.cpp
+    ./test/reactor_test.cpp \
+    ./test/thread_test.cpp
 
 LOCAL_CFLAGS := -Wall -Werror
 LOCAL_MODULE := ositests
diff --git a/osi/include/thread.h b/osi/include/thread.h
new file mode 100644 (file)
index 0000000..8558e92
--- /dev/null
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#define THREAD_NAME_MAX 16
+
+struct thread_t;
+typedef struct thread_t thread_t;
+
+typedef void *(*thread_start_cb) (void *);
+
+// Lifecycle
+thread_t *thread_create(const char *name,
+                         thread_start_cb start_routine, void *arg);
+int thread_join(thread_t *thread, void **retval);
+
+// Query
+pid_t thread_id(const thread_t *thread);
+const char *thread_name(const thread_t *thread);
diff --git a/osi/src/thread.c b/osi/src/thread.c
new file mode 100644 (file)
index 0000000..b81e901
--- /dev/null
@@ -0,0 +1,117 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "osi_thread"
+
+#include <assert.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include "semaphore.h"
+#include "thread.h"
+
+typedef struct thread_t {
+  pthread_t pthread;
+  pid_t tid;
+  char name[THREAD_NAME_MAX+1];
+} thread_t;
+
+pid_t thread_id(const thread_t *thread) {
+  assert(thread != NULL);
+  return thread->tid;
+}
+
+const char *thread_name(const thread_t *thread) {
+  assert(thread != NULL);
+  return thread->name;
+}
+
+struct start_arg {
+  thread_t *thread;
+  semaphore_t *start_sem;
+  int error;
+  thread_start_cb start_routine;
+  void *arg;
+};
+
+static void *run_thread(void *start_arg) {
+  assert(start_arg != NULL);
+
+  struct start_arg *start = start_arg;
+  thread_t *thread = start->thread;
+
+  assert(thread != NULL);
+
+  if (prctl(PR_SET_NAME, (unsigned long)thread->name) == -1) {
+    ALOGE("%s unable to set thread name: %s", __func__, strerror(errno));
+    start->error = errno;
+    semaphore_post(start->start_sem);
+    return NULL;
+  }
+  thread->tid = gettid();
+
+  // Cache local values because we are about to let thread_create
+  // continue
+  thread_start_cb start_routine = start->start_routine;
+  void *arg = start->arg;
+
+  semaphore_post(start->start_sem);
+  return start_routine(arg);
+}
+
+thread_t *thread_create(const char *name,
+                        thread_start_cb start_routine, void *arg) {
+  assert(name != NULL);
+  assert(start_routine != NULL);
+
+  // Start is on the stack, but we use a semaphore, so it's safe
+  struct start_arg start;
+  thread_t *ret;
+  ret = calloc(1, sizeof(thread_t));
+  if (!ret)
+    goto error;
+  start.start_sem = semaphore_new(0);
+  if (!start.start_sem)
+    goto error;
+
+  strncpy(ret->name, name, THREAD_NAME_MAX);
+  start.thread = ret;
+  start.error = 0;
+  start.start_routine = start_routine;
+  start.arg = arg;
+  pthread_create(&ret->pthread, NULL, run_thread, &start);
+  semaphore_wait(start.start_sem);
+  if (start.error)
+    goto error;
+  return ret;
+
+error:;
+  semaphore_free(start.start_sem);
+  free(ret);
+  return NULL;
+}
+
+int thread_join(thread_t *thread, void **retval) {
+  int ret = pthread_join(thread->pthread, retval);
+  if (!ret)
+    free(thread);
+  return ret;
+}
diff --git a/osi/test/thread_test.cpp b/osi/test/thread_test.cpp
new file mode 100644 (file)
index 0000000..bf4c03c
--- /dev/null
@@ -0,0 +1,48 @@
+#include <gtest/gtest.h>
+
+extern "C" {
+#include "thread.h"
+#include "osi.h"
+}
+
+void *start_routine(void *arg)
+{
+  return arg;
+}
+
+TEST(ThreadTest, test_new_simple) {
+  thread_t *thread = thread_create("test_thread", &start_routine, NULL);
+  ASSERT_TRUE(thread != NULL);
+  thread_join(thread, NULL);
+}
+
+TEST(ThreadTest, test_join_simple) {
+  thread_t *thread = thread_create("test_thread", &start_routine, NULL);
+  thread_join(thread, NULL);
+}
+
+TEST(ThreadTest, test_name) {
+  thread_t *thread = thread_create("test_name", &start_routine, NULL);
+  ASSERT_STREQ(thread_name(thread), "test_name");
+  thread_join(thread, NULL);
+}
+
+TEST(ThreadTest, test_long_name) {
+  thread_t *thread = thread_create("0123456789abcdef", &start_routine, NULL);
+  ASSERT_STREQ("0123456789abcdef", thread_name(thread));
+  thread_join(thread, NULL);
+}
+
+TEST(ThreadTest, test_very_long_name) {
+  thread_t *thread = thread_create("0123456789abcdefg", &start_routine, NULL);
+  ASSERT_STREQ("0123456789abcdef", thread_name(thread));
+  thread_join(thread, NULL);
+}
+
+TEST(ThreadTest, test_return) {
+  int arg = 10;
+  void *ret;
+  thread_t *thread = thread_create("test", &start_routine, &arg);
+  thread_join(thread, &ret);
+  ASSERT_EQ(ret, &arg);
+}