1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <pthread.h>
7#include <stdlib.h>
8
9#include "base/macros.h"
10#include "base/memory/scoped_ptr.h"
11#include "components/nacl/loader/nonsfi/irt_interfaces.h"
12
13namespace nacl {
14namespace nonsfi {
15namespace {
16
17// We heuristically chose 1M for the stack size per thread.
18const int kStackSize = 1024 * 1024;
19
20// For RAII of pthread_attr_t.
21class ScopedPthreadAttrPtr {
22 public:
23  ScopedPthreadAttrPtr(pthread_attr_t* attr) : attr_(attr) {
24  }
25  ~ScopedPthreadAttrPtr() {
26    pthread_attr_destroy(attr_);
27  }
28
29 private:
30  pthread_attr_t* attr_;
31};
32
33struct ThreadContext {
34  void (*start_func)();
35  void* thread_ptr;
36};
37
38// A thread local pointer to support nacl_irt_tls.
39// This should be initialized at the beginning of ThreadMain, which is a thin
40// wrapper of a user function called on a newly created thread, and may be
41// reset via IrtTlsInit(). The pointer can be obtained via IrtTlsGet().
42__thread void* g_thread_ptr;
43
44void* ThreadMain(void *arg) {
45  ::scoped_ptr<ThreadContext> context(static_cast<ThreadContext*>(arg));
46  g_thread_ptr = context->thread_ptr;
47
48  // Release the memory of context before running start_func.
49  void (*start_func)() = context->start_func;
50  context.reset();
51
52  start_func();
53  abort();
54}
55
56int IrtThreadCreate(void (*start_func)(), void* stack, void* thread_ptr) {
57  pthread_attr_t attr;
58  int error = pthread_attr_init(&attr);
59  if (error != 0)
60    return error;
61  ScopedPthreadAttrPtr scoped_attr_ptr(&attr);
62
63  // Note: Currently we ignore the argument stack.
64  error = pthread_attr_setstacksize(&attr, kStackSize);
65  if (error != 0)
66    return error;
67
68  error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
69  if (error != 0)
70    return error;
71
72  ::scoped_ptr<ThreadContext> context(new ThreadContext);
73  context->start_func = start_func;
74  context->thread_ptr = thread_ptr;
75
76  pthread_t tid;
77  error = pthread_create(&tid, &attr, ThreadMain, context.get());
78  if (error != 0)
79    return error;
80
81  // The ownership of the context is taken by the created thread. So, here we
82  // just manually release it.
83  ignore_result(context.release());
84  return 0;
85}
86
87void IrtThreadExit(int32_t* stack_flag) {
88  // As we actually don't use stack given to thread_create, it means that the
89  // memory can be released whenever.
90  if (stack_flag)
91    *stack_flag = 0;
92  pthread_exit(NULL);
93}
94
95int IrtThreadNice(const int nice) {
96  // TODO(https://code.google.com/p/nativeclient/issues/detail?id=3734):
97  // Implement this method.
98  // Note that this is just a hint, so here we just return success without
99  // do anything.
100  return 0;
101}
102
103int IrtTlsInit(void* thread_ptr) {
104  g_thread_ptr = thread_ptr;
105  return 0;
106}
107
108void* IrtTlsGet() {
109  return g_thread_ptr;
110}
111
112}  // namespace
113
114const nacl_irt_thread kIrtThread = {
115  IrtThreadCreate,
116  IrtThreadExit,
117  IrtThreadNice,
118};
119
120const nacl_irt_tls kIrtTls = {
121  IrtTlsInit,
122  IrtTlsGet,
123};
124
125}  // namespace nonsfi
126}  // namespace nacl
127