1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
/*
* Copyright (c) 2011 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* NaCl Server Runtime threads implementation layer.
*/
#include <stdlib.h>
/*
* We need sys/mman.h for PAGE_SIZE on Android. PAGE_SIZE is what
* PTHREAD_STACK_MIN defined to, so Android's pthread.h is somewhat
* buggy in that regard.
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <signal.h>
#include <pthread.h>
#include <limits.h>
/*
* PTHREAD_STACK_MIN should come from pthread.h as documented, but is
* actually pulled in by limits.h.
*/
#include "native_client/src/include/portability.h"
#include "native_client/src/shared/platform/nacl_log.h"
#include "native_client/src/shared/platform/nacl_threads.h"
#include "native_client/src/trusted/service_runtime/nacl_config.h"
#if !defined(__native_client__) && NACL_KERN_STACK_SIZE < PTHREAD_STACK_MIN
# error "NaCl service runtime stack size is smaller than PTHREAD_STACK_MIN"
#endif
static int NaClThreadCreate(struct NaClThread *ntp,
void (*start_fn)(void *),
void *state,
size_t stack_size,
int is_detached) {
pthread_attr_t attr;
int code;
int rv;
rv = 0;
if (stack_size < PTHREAD_STACK_MIN) {
stack_size = PTHREAD_STACK_MIN;
}
if (0 != (code = pthread_attr_init(&attr))) {
NaClLog(LOG_ERROR,
"NaClThreadCtor: pthread_atr_init returned %d",
code);
goto done;
}
if (0 != (code = pthread_attr_setstacksize(&attr, stack_size))) {
NaClLog(LOG_ERROR,
"NaClThreadCtor: pthread_attr_setstacksize returned %d",
code);
goto done_attr_dtor;
}
if (is_detached) {
if (0 != (code = pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_DETACHED))) {
NaClLog(LOG_ERROR,
"nacl_thread: pthread_attr_setdetachstate returned %d",
code);
goto done_attr_dtor;
}
}
if (0 != (code = pthread_create(&ntp->tid,
&attr,
(void *(*)(void *)) start_fn,
state))) {
NaClLog(LOG_ERROR,
"nacl_thread: pthread_create returned %d",
code);
goto done_attr_dtor;
}
rv = 1;
done_attr_dtor:
(void) pthread_attr_destroy(&attr); /* often a noop */
done:
return rv;
}
/*
* Even if ctor fails, it should be okay -- and required -- to invoke
* the dtor on it.
*/
int NaClThreadCtor(struct NaClThread *ntp,
void (*start_fn)(void *),
void *state,
size_t stack_size) {
return NaClThreadCreate(ntp, start_fn, state, stack_size,
/* is_detached= */ 1);
}
int NaClThreadCreateJoinable(struct NaClThread *ntp,
void (*start_fn)(void *),
void *state,
size_t stack_size) {
return NaClThreadCreate(ntp, start_fn, state, stack_size,
/* is_detached= */ 0);
}
void NaClThreadDtor(struct NaClThread *ntp) {
/*
* The threads that we create are not joinable, and we cannot tell
* when they are truly gone. Fortunately, the threads themselves
* and the underlying thread library are responsible for ensuring
* that resources such as the thread stack are properly released.
*/
UNREFERENCED_PARAMETER(ntp);
}
void NaClThreadJoin(struct NaClThread *ntp) {
pthread_join(ntp->tid, NULL);
}
void NaClThreadExit(void) {
pthread_exit(NULL);
}
void NaClThreadYield(void) {
sched_yield();
}
|