The International Simutrans Forum

Development => Patches & Projects => Incorporated Patches and Solved Bug Reports => Topic started by: Kernigh on December 04, 2018, 10:45:45 PM

Title: Patch for recursive mutexes without initializer
Post by: Kernigh on December 04, 2018, 10:45:45 PM
Simutrans with MULTI_THREAD = 1 requires Linux glibc (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) or macOS (PTHREAD_RECURSIVE_MUTEX_INITIALIZER), so we can't enable MULTI_THREAD = 1 on other platforms.

I modify a patch from TurfIt (https://forum.simutrans.com/index.php/topic,18587.msg176592.html#msg176592) and attach the modified patch. It's a git diff; use patch -p1 or git apply. This patch allows me to enable MULTI_THREAD = 1 on OpenBSD/amd64, and might help other platforms, but I did not test the patch on other platforms.

I add a new type recursive_mutex_maker_t. Its constructor takes a reference to a pthread_mutex_t and makes it into a recursive mutex.


/* old way */
static pthread_mutex_t weg_calc_image_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

/* new way */
static pthread_mutex_t weg_calc_image_mutex;
static recursive_mutex_maker_t weg_cim_maker(weg_calc_image_mutex);


The new constructor tries to use the same initializer as the old code.


#if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
// Linux glibc
#define _SIMTHREAD_R_MUTEX_I PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
#elif defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER
// Mac OS X
#define _SIMTHREAD_R_MUTEX_I PTHREAD_RECURSIVE_MUTEX_INITIALIZER
#endif

struct recursive_mutex_maker_t {
#ifdef _SIMTHREAD_R_MUTEX_I
recursive_mutex_maker_t(pthread_mutex_t &mutex) {
mutex = _SIMTHREAD_R_MUTEX_I;
}
#else
recursive_mutex_maker_t(pthread_mutex_t &mutex);
#endif
};


If there is no such initializer, the constructor calls pthread_mutex_init(). This is the only way to make a recursive pthread_mutex_t in OpenBSD.


#ifndef _SIMTHREAD_R_MUTEX_I
// initialize a recursive mutex by calling pthread_mutex_init()
#include <stdexcept>


recursive_mutex_maker_t::recursive_mutex_maker_t(pthread_mutex_t &mutex) {
pthread_mutexattr_t attr;

if (pthread_mutexattr_init(&attr) != 0 ||
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0 ||
    pthread_mutex_init(&mutex, &attr) != 0 ||
    pthread_mutexattr_destroy(&attr) != 0) {
// Can't call dbg->error(), because this constructor
// may run before simu_main() calls init_logging().
throw std::runtime_error("Can't make a recursive mutex!");
}
}
#endif


I link to pthread.h from FreeBSD (https://svnweb.freebsd.org/base/head/include/pthread.h?revision=337992&view=markup), Haiku (https://git.haiku-os.org/haiku/tree/headers/posix/pthread.h), illumos (https://github.com/illumos/illumos-gate/blob/master/usr/src/head/pthread.h), NetBSD (http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libpthread/pthread.h?rev=1.41&content-type=text/x-cvsweb-markup&only_with_tag=MAIN), OpenBSD (https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/include/pthread.h?rev=1.4&content-type=text/x-cvsweb-markup), Linux glibc (https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/nptl/pthread.h;h=df049abf74d4752280b81d6eacd7dc7e454a61b5;hb=HEAD), Linux musl (https://git.musl-libc.org/cgit/musl/tree/include/pthread.h), macOS (https://opensource.apple.com/source/libpthread/libpthread-330.201.1/pthread/pthread.h.auto.html), Windows winpthreads (https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-libraries/winpthreads/include/pthread.h). All of these define PTHREAD_MUTEX_RECURSIVE. Linux glibc and Windows winpthreads define both PTHREAD_MUTEX_RECURSIVE and PTHREAD_MUTEX_RECURSIVE_NP. Linux glibc may hide the definition of PTHREAD_MUTEX_RECURSIVE. This patch doesn't try PTHREAD_MUTEX_RECURSIVE_NP, because it tries PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP on Linux glibc.

Because recursive_mutex_maker_t only has a constructor, it doesn't have its own lock and unlock methods, so the patch doesn't change the calls to pthread_mutex_lock() or pthread_mutex_unlock(). The existing calls to pthread_mutex_lock() don't check for errors, so they might not lock the mutex if an error happened. I don't want to give an uninitialized mutex to pthread_mutex_lock() -- it might cause pthread_mutex_lock() to misbehave or crash -- so this patch tries to check that pthread_mutex_init() does initialize each mutex.
Title: Re: Patch for recursive mutexes without initializer
Post by: prissi on March 21, 2019, 02:50:22 AM
Maybe that was also the trouble on loading Haiku games. Incorporated in r8729, thank you!