blob: 3351bdc48b1dbbfee29eb063a668f6f1c7e102b6 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "components/nacl/loader/nonsfi/irt_interfaces.h"
namespace nacl {
namespace nonsfi {
namespace {
// We heuristically chose 1M for the stack size per thread.
const int kStackSize = 1024 * 1024;
// For RAII of pthread_attr_t.
class ScopedPthreadAttrPtr {
public:
ScopedPthreadAttrPtr(pthread_attr_t* attr) : attr_(attr) {
}
~ScopedPthreadAttrPtr() {
pthread_attr_destroy(attr_);
}
private:
pthread_attr_t* attr_;
};
struct ThreadContext {
void (*start_func)();
void* thread_ptr;
};
// A thread local pointer to support nacl_irt_tls.
// This should be initialized at the beginning of ThreadMain, which is a thin
// wrapper of a user function called on a newly created thread, and may be
// reset via IrtTlsInit(). The pointer can be obtained via IrtTlsGet().
__thread void* g_thread_ptr;
void* ThreadMain(void *arg) {
::scoped_ptr<ThreadContext> context(static_cast<ThreadContext*>(arg));
g_thread_ptr = context->thread_ptr;
// Release the memory of context before running start_func.
void (*start_func)() = context->start_func;
context.reset();
start_func();
abort();
}
int IrtThreadCreate(void (*start_func)(), void* stack, void* thread_ptr) {
pthread_attr_t attr;
int error = pthread_attr_init(&attr);
if (error != 0)
return error;
ScopedPthreadAttrPtr scoped_attr_ptr(&attr);
// Note: Currently we ignore the argument stack.
error = pthread_attr_setstacksize(&attr, kStackSize);
if (error != 0)
return error;
error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (error != 0)
return error;
::scoped_ptr<ThreadContext> context(new ThreadContext);
context->start_func = start_func;
context->thread_ptr = thread_ptr;
pthread_t tid;
error = pthread_create(&tid, &attr, ThreadMain, context.get());
if (error != 0)
return error;
// The ownership of the context is taken by the created thread. So, here we
// just manually release it.
ignore_result(context.release());
return 0;
}
void IrtThreadExit(int32_t* stack_flag) {
// As we actually don't use stack given to thread_create, it means that the
// memory can be released whenever.
if (stack_flag)
*stack_flag = 0;
pthread_exit(NULL);
}
int IrtThreadNice(const int nice) {
// TODO(https://code.google.com/p/nativeclient/issues/detail?id=3734):
// Implement this method.
// Note that this is just a hint, so here we just return success without
// do anything.
return 0;
}
int IrtTlsInit(void* thread_ptr) {
g_thread_ptr = thread_ptr;
return 0;
}
void* IrtTlsGet() {
return g_thread_ptr;
}
} // namespace
const nacl_irt_thread kIrtThread = {
IrtThreadCreate,
IrtThreadExit,
IrtThreadNice,
};
const nacl_irt_tls kIrtTls = {
IrtTlsInit,
IrtTlsGet,
};
} // namespace nonsfi
} // namespace nacl