Make macros thread-safe ... sort of

- Add the actual locking into macro context acquire + release. We're
  using a mutex instead of rwlock because currently any macro can
  involve defines and undefines and we dont know it beforehand. So
  we just use a bigger hammer...
- The macro engine internals shouldn't need recursive mutexes but
  unfortunately Lua macro bindings, which are limited to the
  lock-on-entry interfaces can and do get called recursively
  from macros so currently there's not much choice but to use
  recursive mutex for the macro contexts. What makes it even uglier
  is that there's no portable static initializer for recursive mutex
  so we need to add yet another pthread-construct to safely dynamically
  initialize the mutexes :(
- Of course this doesn't make bunch of threads simultaneously messing
  with macros behave sane: if one thread tries to load new macros
  and the other one frees them, they shouldn't crash but the
  results are unlikely to be what the caller intended. The purpose
  here is just to allow the occasional rpmExpand() and such to
  complete without crashing and burning when multiple threads are
  doing stuff like trying to read packages from disk.
This commit is contained in:
Panu Matilainen 2013-05-22 14:24:29 +03:00
parent 09499d994b
commit 71e2d38e3d
1 changed files with 29 additions and 0 deletions

View File

@ -4,6 +4,7 @@
#include "system.h"
#include <stdarg.h>
#include <pthread.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
@ -49,6 +50,8 @@ struct rpmMacroEntry_s {
struct rpmMacroContext_s {
rpmMacroEntry *tab; /*!< Macro entry table (array of pointers). */
int n; /*!< No. of macros. */
pthread_mutex_t lock;
pthread_mutexattr_t lockattr;
};
@ -58,6 +61,29 @@ rpmMacroContext rpmGlobalMacroContext = &rpmGlobalMacroContext_s;
static struct rpmMacroContext_s rpmCLIMacroContext_s;
rpmMacroContext rpmCLIMacroContext = &rpmCLIMacroContext_s;
/*
* The macro engine internals do not require recursive mutexes but Lua
* macro bindings which can get called from the internals use the external
* interfaces which do perform locking. Until that is fixed somehow
* we'll just have to settle for recursive mutexes.
* Unfortunately POSIX doesn't specify static initializers for recursive
* mutexes so we need to have a separate PTHREAD_ONCE initializer just
* to initialize the otherwise static macro context mutexes. Pooh.
*/
static pthread_once_t locksInitialized = PTHREAD_ONCE_INIT;
static void initLocks(void)
{
rpmMacroContext mcs[] = { rpmGlobalMacroContext, rpmCLIMacroContext, NULL };
for (rpmMacroContext *mcp = mcs; *mcp; mcp++) {
rpmMacroContext mc = *mcp;
pthread_mutexattr_init(&mc->lockattr);
pthread_mutexattr_settype(&mc->lockattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mc->lock, &mc->lockattr);
}
}
/**
* Macro expansion state.
*/
@ -92,11 +118,14 @@ static rpmMacroContext rpmmctxAcquire(rpmMacroContext mc)
{
if (mc == NULL)
mc = rpmGlobalMacroContext;
pthread_once(&locksInitialized, initLocks);
pthread_mutex_lock(&mc->lock);
return mc;
}
static rpmMacroContext rpmmctxRelease(rpmMacroContext mc)
{
pthread_mutex_unlock(&mc->lock);
return NULL;
}