mirror of
https://github.com/luanti-org/luanti.git
synced 2025-07-22 17:18:39 +00:00
Clean up threading
* Rename everything. * Strip J prefix. * Change UpperCamelCase functions to lowerCamelCase. * Remove global (!) semaphore count mutex on OSX. * Remove semaphore count getter (unused, unsafe, depended on internal API functions on Windows, and used a hack on OSX). * Add `Atomic<type>`. * Make `Thread` handle thread names. * Add support for C++11 multi-threading. * Combine pthread and win32 sources. * Remove `ThreadStarted` (unused, unneeded). * Move some includes from the headers to the sources. * Move all of `Event` into its header (allows inlining with no new includes). * Make `Event` use `Semaphore` (except on Windows). * Move some porting functions into `Thread`. * Integrate logging with `Thread`. * Add threading test.
This commit is contained in:
parent
6a1047d8c1
commit
e4bff8be94
77 changed files with 1594 additions and 2046 deletions
161
src/threading/semaphore.cpp
Normal file
161
src/threading/semaphore.cpp
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 sapier <sapier AT gmx DOT net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "threading/semaphore.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#define UNUSED(expr) do { (void)(expr); } while (0)
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MAX_SEMAPHORE_COUNT LONG_MAX - 1
|
||||
#else
|
||||
#include <cerrno>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#if defined(__MACH__) && defined(__APPLE__)
|
||||
#include <mach/mach.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach/semaphore.h>
|
||||
#include <sys/semaphore.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#undef sem_t
|
||||
#undef sem_init
|
||||
#undef sem_wait
|
||||
#undef sem_post
|
||||
#undef sem_destroy
|
||||
#define sem_t semaphore_t
|
||||
#define sem_init(s, p, c) semaphore_create(mach_task_self(), (s), 0, (c))
|
||||
#define sem_wait(s) semaphore_wait(*(s))
|
||||
#define sem_post(s) semaphore_signal(*(s))
|
||||
#define sem_destroy(s) semaphore_destroy(mach_task_self(), *(s))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
Semaphore::Semaphore(int val)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
semaphore = CreateSemaphore(NULL, val, MAX_SEMAPHORE_COUNT, NULL);
|
||||
#else
|
||||
int ret = sem_init(&semaphore, 0, val);
|
||||
assert(!ret);
|
||||
UNUSED(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(semaphore);
|
||||
#else
|
||||
int ret = sem_destroy(&semaphore);
|
||||
#ifdef __ANDROID__
|
||||
// Workaround for broken bionic semaphore implementation!
|
||||
assert(!ret || errno == EBUSY);
|
||||
#else
|
||||
assert(!ret);
|
||||
#endif
|
||||
UNUSED(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Semaphore::post(unsigned int num)
|
||||
{
|
||||
assert(num > 0);
|
||||
#ifdef _WIN32
|
||||
ReleaseSemaphore(semaphore, num, NULL);
|
||||
#else
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
int ret = sem_post(&semaphore);
|
||||
assert(!ret);
|
||||
UNUSED(ret);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Semaphore::wait()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WaitForSingleObject(semaphore, INFINITE);
|
||||
#else
|
||||
int ret = sem_wait(&semaphore);
|
||||
assert(!ret);
|
||||
UNUSED(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool Semaphore::wait(unsigned int time_ms)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned int ret = WaitForSingleObject(semaphore, time_ms);
|
||||
|
||||
if (ret == WAIT_OBJECT_0) {
|
||||
return true;
|
||||
} else {
|
||||
assert(ret == WAIT_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
# if defined(__MACH__) && defined(__APPLE__)
|
||||
mach_timespec_t wait_time;
|
||||
wait_time.tv_sec = time_ms / 1000;
|
||||
wait_time.tv_nsec = 1000000 * (time_ms % 1000);
|
||||
|
||||
errno = 0;
|
||||
int ret = semaphore_timedwait(semaphore, wait_time);
|
||||
switch (ret) {
|
||||
case KERN_OPERATION_TIMED_OUT:
|
||||
errno = ETIMEDOUT;
|
||||
break;
|
||||
case KERN_ABORTED:
|
||||
errno = EINTR;
|
||||
break;
|
||||
default:
|
||||
if (ret)
|
||||
errno = EINVAL;
|
||||
}
|
||||
# else
|
||||
struct timespec wait_time;
|
||||
struct timeval now;
|
||||
|
||||
if (gettimeofday(&now, NULL) == -1) {
|
||||
std::cerr << "Semaphore::wait(ms): Unable to get time with gettimeofday!" << std::endl;
|
||||
abort();
|
||||
}
|
||||
|
||||
wait_time.tv_nsec = ((time_ms % 1000) * 1000 * 1000) + (now.tv_usec * 1000);
|
||||
wait_time.tv_sec = (time_ms / 1000) + (wait_time.tv_nsec / (1000 * 1000 * 1000)) + now.tv_sec;
|
||||
wait_time.tv_nsec %= 1000 * 1000 * 1000;
|
||||
|
||||
int ret = sem_timedwait(&semaphore, &wait_time);
|
||||
# endif
|
||||
|
||||
assert(!ret || (errno == ETIMEDOUT || errno == EINTR));
|
||||
return !ret;
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue