blob: 96c53f7bb3cdac8aa914d1990b45a0eed045c74b [file] [log] [blame]
// Copyright 2016 The Cobalt Authors. All Rights Reserved.
//
// 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.
#include "starboard/thread.h"
#include <pthread.h>
#include <sched.h>
#include <sys/resource.h>
#include <unistd.h>
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/shared/pthread/is_success.h"
#include "starboard/shared/pthread/thread_create_priority.h"
#include "starboard/shared/pthread/types_internal.h"
namespace starboard {
namespace shared {
namespace pthread {
#if SB_API_VERSION < 12 && !SB_HAS(THREAD_PRIORITY_SUPPORT)
// Default implementation without thread priority support
void ThreadSetPriority(SbThreadPriority priority) {}
#endif
} // namespace pthread
} // namespace shared
} // namespace starboard
namespace {
struct ThreadParams {
SbThreadAffinity affinity;
SbThreadEntryPoint entry_point;
char name[128];
void* context;
SbThreadPriority priority;
};
void* ThreadFunc(void* context) {
ThreadParams* thread_params = static_cast<ThreadParams*>(context);
SbThreadEntryPoint entry_point = thread_params->entry_point;
void* real_context = thread_params->context;
SbThreadAffinity affinity = thread_params->affinity;
if (thread_params->name[0] != '\0') {
SbThreadSetName(thread_params->name);
}
starboard::shared::pthread::ThreadSetPriority(thread_params->priority);
delete thread_params;
#if !SB_HAS_QUIRK(THREAD_AFFINITY_UNSUPPORTED)
if (SbThreadIsValidAffinity(affinity)) {
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(affinity, &cpu_set);
sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
}
#endif
return entry_point(real_context);
}
} // namespace
SbThread SbThreadCreate(int64_t stack_size,
SbThreadPriority priority,
SbThreadAffinity affinity,
bool joinable,
const char* name,
SbThreadEntryPoint entry_point,
void* context) {
if (stack_size < 0 || !entry_point) {
return kSbThreadInvalid;
}
#if defined(ADDRESS_SANITIZER)
// Set a big thread stack size when in ADDRESS_SANITIZER mode.
// This eliminates buffer overflows for deeply nested callstacks.
if (stack_size == 0) {
stack_size = 4096 * 1024; // 4MB
}
#endif
pthread_attr_t attributes;
int result = pthread_attr_init(&attributes);
if (!IsSuccess(result)) {
return kSbThreadInvalid;
}
pthread_attr_setdetachstate(
&attributes,
(joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
if (stack_size > 0) {
pthread_attr_setstacksize(&attributes, stack_size);
}
ThreadParams* params = new ThreadParams();
params->affinity = affinity;
params->entry_point = entry_point;
params->context = context;
if (name) {
SbStringCopy(params->name, name, SB_ARRAY_SIZE_INT(params->name));
} else {
params->name[0] = '\0';
}
params->priority = priority;
SbThread thread = kSbThreadInvalid;
SB_COMPILE_ASSERT(sizeof(SbThread) >= sizeof(pthread_t),
pthread_t_larger_than_sb_thread);
result = pthread_create(SB_PTHREAD_INTERNAL_THREAD_PTR(thread), &attributes,
ThreadFunc, params);
pthread_attr_destroy(&attributes);
if (IsSuccess(result)) {
return thread;
}
return kSbThreadInvalid;
}