Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74c0773baa | ||
|
|
0848171c94 | ||
|
|
233fb91364 | ||
|
|
044847012c | ||
|
|
5268cc6dc3 | ||
|
|
63fa740886 | ||
|
|
49bcfaad74 |
No files matched your search
+55
-8
@@ -53,6 +53,7 @@
|
||||
#include "zmalloc.h"
|
||||
#include "config.h"
|
||||
#include "serverassert.h"
|
||||
#include "readwritelock.h"
|
||||
|
||||
#ifdef USE_MUTEX
|
||||
thread_local int cOwnLock = 0;
|
||||
@@ -87,6 +88,7 @@ mutex_wrapper g_lock;
|
||||
#else
|
||||
fastlock g_lock("AE (global)");
|
||||
#endif
|
||||
readWriteLock g_forkLock("Fork (global)");
|
||||
thread_local aeEventLoop *g_eventLoopThisThread = NULL;
|
||||
|
||||
/* Include the best multiplexing layer supported by this system.
|
||||
@@ -151,8 +153,11 @@ void aeProcessCmd(aeEventLoop *eventLoop, int fd, void *, int )
|
||||
case AE_ASYNC_OP::PostFunction:
|
||||
{
|
||||
std::unique_lock<decltype(g_lock)> ulock(g_lock, std::defer_lock);
|
||||
if (cmd.fLock)
|
||||
if (cmd.fLock) {
|
||||
g_forkLock.releaseRead();
|
||||
ulock.lock();
|
||||
g_forkLock.acquireRead();
|
||||
}
|
||||
((aePostFunctionProc*)cmd.proc)(cmd.clientData);
|
||||
break;
|
||||
}
|
||||
@@ -160,8 +165,11 @@ void aeProcessCmd(aeEventLoop *eventLoop, int fd, void *, int )
|
||||
case AE_ASYNC_OP::PostCppFunction:
|
||||
{
|
||||
std::unique_lock<decltype(g_lock)> ulock(g_lock, std::defer_lock);
|
||||
if (cmd.fLock)
|
||||
if (cmd.fLock) {
|
||||
g_forkLock.releaseRead();
|
||||
ulock.lock();
|
||||
g_forkLock.acquireRead();
|
||||
}
|
||||
(*cmd.pfn)();
|
||||
|
||||
delete cmd.pfn;
|
||||
@@ -545,7 +553,11 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
|
||||
if (te->next)
|
||||
te->next->prev = te->prev;
|
||||
if (te->finalizerProc) {
|
||||
if (!ulock.owns_lock()) ulock.lock();
|
||||
if (!ulock.owns_lock()) {
|
||||
g_forkLock.releaseRead();
|
||||
ulock.lock();
|
||||
g_forkLock.acquireRead();
|
||||
}
|
||||
te->finalizerProc(eventLoop, te->clientData);
|
||||
now = getMonotonicUs();
|
||||
}
|
||||
@@ -565,7 +577,11 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
|
||||
}
|
||||
|
||||
if (te->when <= now) {
|
||||
if (!ulock.owns_lock()) ulock.lock();
|
||||
if (!ulock.owns_lock()) {
|
||||
g_forkLock.releaseRead();
|
||||
ulock.lock();
|
||||
g_forkLock.acquireRead();
|
||||
}
|
||||
int retval;
|
||||
|
||||
id = te->id;
|
||||
@@ -589,8 +605,11 @@ extern "C" void ProcessEventCore(aeEventLoop *eventLoop, aeFileEvent *fe, int ma
|
||||
{
|
||||
#define LOCK_IF_NECESSARY(fe, tsmask) \
|
||||
std::unique_lock<decltype(g_lock)> ulock(g_lock, std::defer_lock); \
|
||||
if (!(fe->mask & tsmask)) \
|
||||
ulock.lock()
|
||||
if (!(fe->mask & tsmask)) { \
|
||||
g_forkLock.releaseRead(); \
|
||||
ulock.lock(); \
|
||||
g_forkLock.acquireRead(); \
|
||||
}
|
||||
|
||||
int fired = 0; /* Number of events fired for current fd. */
|
||||
|
||||
@@ -702,8 +721,11 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
|
||||
|
||||
if (eventLoop->beforesleep != NULL && flags & AE_CALL_BEFORE_SLEEP) {
|
||||
std::unique_lock<decltype(g_lock)> ulock(g_lock, std::defer_lock);
|
||||
if (!(eventLoop->beforesleepFlags & AE_SLEEP_THREADSAFE))
|
||||
if (!(eventLoop->beforesleepFlags & AE_SLEEP_THREADSAFE)) {
|
||||
g_forkLock.releaseRead();
|
||||
ulock.lock();
|
||||
g_forkLock.acquireRead();
|
||||
}
|
||||
eventLoop->beforesleep(eventLoop);
|
||||
}
|
||||
|
||||
@@ -714,8 +736,11 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
|
||||
/* After sleep callback. */
|
||||
if (eventLoop->aftersleep != NULL && flags & AE_CALL_AFTER_SLEEP) {
|
||||
std::unique_lock<decltype(g_lock)> ulock(g_lock, std::defer_lock);
|
||||
if (!(eventLoop->aftersleepFlags & AE_SLEEP_THREADSAFE))
|
||||
if (!(eventLoop->aftersleepFlags & AE_SLEEP_THREADSAFE)) {
|
||||
g_forkLock.releaseRead();
|
||||
ulock.lock();
|
||||
g_forkLock.acquireRead();
|
||||
}
|
||||
eventLoop->aftersleep(eventLoop);
|
||||
}
|
||||
|
||||
@@ -789,9 +814,21 @@ void setAeLockSetThreadSpinWorker(spin_worker worker)
|
||||
tl_worker = worker;
|
||||
}
|
||||
|
||||
void aeThreadOnline()
|
||||
{
|
||||
g_forkLock.acquireRead();
|
||||
}
|
||||
|
||||
void aeAcquireLock()
|
||||
{
|
||||
g_forkLock.releaseRead();
|
||||
g_lock.lock(tl_worker);
|
||||
g_forkLock.acquireRead();
|
||||
}
|
||||
|
||||
void aeAcquireForkLock()
|
||||
{
|
||||
g_forkLock.upgradeWrite();
|
||||
}
|
||||
|
||||
int aeTryAcquireLock(int fWeak)
|
||||
@@ -799,11 +836,21 @@ int aeTryAcquireLock(int fWeak)
|
||||
return g_lock.try_lock(!!fWeak);
|
||||
}
|
||||
|
||||
void aeThreadOffline()
|
||||
{
|
||||
g_forkLock.releaseRead();
|
||||
}
|
||||
|
||||
void aeReleaseLock()
|
||||
{
|
||||
g_lock.unlock();
|
||||
}
|
||||
|
||||
void aeReleaseForkLock()
|
||||
{
|
||||
g_forkLock.downgradeWrite();
|
||||
}
|
||||
|
||||
int aeThreadOwnsLock()
|
||||
{
|
||||
return g_lock.fOwnLock();
|
||||
|
||||
@@ -164,9 +164,13 @@ void aeSetDontWait(aeEventLoop *eventLoop, int noWait);
|
||||
void aeClosePipesForForkChild(aeEventLoop *eventLoop);
|
||||
|
||||
void setAeLockSetThreadSpinWorker(spin_worker worker);
|
||||
void aeThreadOnline();
|
||||
void aeAcquireLock();
|
||||
void aeAcquireForkLock();
|
||||
int aeTryAcquireLock(int fWeak);
|
||||
void aeThreadOffline();
|
||||
void aeReleaseLock();
|
||||
void aeReleaseForkLock();
|
||||
int aeThreadOwnsLock();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
+1
-1
@@ -365,7 +365,7 @@ typedef struct RedisModuleCommandFilter {
|
||||
static list *moduleCommandFilters;
|
||||
|
||||
/* Module GIL Variables */
|
||||
static readWriteLock s_moduleGIL;
|
||||
static readWriteLock s_moduleGIL("Module GIL");
|
||||
thread_local bool g_fModuleThread = false;
|
||||
|
||||
typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data);
|
||||
|
||||
+15
-32
@@ -2,22 +2,24 @@
|
||||
#include <condition_variable>
|
||||
|
||||
class readWriteLock {
|
||||
std::mutex m_readLock;
|
||||
std::recursive_mutex m_writeLock;
|
||||
std::condition_variable m_cv;
|
||||
fastlock m_readLock;
|
||||
fastlock m_writeLock;
|
||||
std::condition_variable_any m_cv;
|
||||
int m_readCount = 0;
|
||||
int m_writeCount = 0;
|
||||
bool m_writeWaiting = false;
|
||||
public:
|
||||
readWriteLock(const char *name) : m_readLock(name), m_writeLock(name) {}
|
||||
|
||||
void acquireRead() {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
while (m_writeCount > 0 || m_writeWaiting)
|
||||
m_cv.wait(rm);
|
||||
m_readCount++;
|
||||
}
|
||||
|
||||
bool tryAcquireRead() {
|
||||
std::unique_lock<std::mutex> rm(m_readLock, std::defer_lock);
|
||||
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
|
||||
if (!rm.try_lock())
|
||||
return false;
|
||||
if (m_writeCount > 0 || m_writeWaiting)
|
||||
@@ -27,7 +29,7 @@ public:
|
||||
}
|
||||
|
||||
void acquireWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
m_writeWaiting = true;
|
||||
while (m_readCount > 0)
|
||||
m_cv.wait(rm);
|
||||
@@ -43,24 +45,12 @@ public:
|
||||
}
|
||||
|
||||
void upgradeWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
m_writeWaiting = true;
|
||||
while (m_readCount > 1)
|
||||
m_cv.wait(rm);
|
||||
if (exclusive) {
|
||||
/* Another thread might have the write lock while we have the read lock
|
||||
but won't be able to release it until they can acquire the read lock
|
||||
so release the read lock and try again instead of waiting to avoid deadlock */
|
||||
while(!m_writeLock.try_lock())
|
||||
m_cv.wait(rm);
|
||||
}
|
||||
m_writeCount++;
|
||||
m_readCount--;
|
||||
m_writeWaiting = false;
|
||||
releaseRead();
|
||||
acquireWrite(exclusive);
|
||||
}
|
||||
|
||||
bool tryAcquireWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock, std::defer_lock);
|
||||
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
|
||||
if (!rm.try_lock())
|
||||
return false;
|
||||
if (m_readCount > 0)
|
||||
@@ -73,14 +63,13 @@ public:
|
||||
}
|
||||
|
||||
void releaseRead() {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
serverAssert(m_readCount > 0);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
m_readCount--;
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
void releaseWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
serverAssert(m_writeCount > 0);
|
||||
if (exclusive)
|
||||
m_writeLock.unlock();
|
||||
@@ -89,14 +78,8 @@ public:
|
||||
}
|
||||
|
||||
void downgradeWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
serverAssert(m_writeCount > 0);
|
||||
if (exclusive)
|
||||
m_writeLock.unlock();
|
||||
m_writeCount--;
|
||||
while (m_writeCount > 0 || m_writeWaiting)
|
||||
m_cv.wait(rm);
|
||||
m_readCount++;
|
||||
releaseWrite(exclusive);
|
||||
acquireRead();
|
||||
}
|
||||
|
||||
bool hasReader() {
|
||||
|
||||
+23
-17
@@ -62,7 +62,6 @@
|
||||
#include <sys/socket.h>
|
||||
#include <algorithm>
|
||||
#include <uuid/uuid.h>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include "aelocker.h"
|
||||
#include "motd.h"
|
||||
@@ -92,14 +91,12 @@ double R_Zero, R_PosInf, R_NegInf, R_Nan;
|
||||
/* Global vars */
|
||||
namespace GlobalHidden {
|
||||
struct redisServer server; /* Server global state */
|
||||
readWriteLock forkLock;
|
||||
}
|
||||
redisServer *g_pserver = &GlobalHidden::server;
|
||||
readWriteLock *g_forkLock = &GlobalHidden::forkLock;
|
||||
struct redisServerConst cserver;
|
||||
__thread struct redisServerThreadVars *serverTL = NULL; // thread local server vars
|
||||
std::mutex time_thread_mutex;
|
||||
std::condition_variable time_thread_cv;
|
||||
fastlock time_thread_lock("Time thread lock");
|
||||
std::condition_variable_any time_thread_cv;
|
||||
int sleeping_threads = 0;
|
||||
void wakeTimeThread();
|
||||
|
||||
@@ -2626,9 +2623,10 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
|
||||
if (!fSentReplies)
|
||||
handleClientsWithPendingWrites(iel, aof_state);
|
||||
|
||||
aeThreadOffline();
|
||||
// Scope lock_guard
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(time_thread_mutex);
|
||||
std::unique_lock<fastlock> lock(time_thread_lock);
|
||||
sleeping_threads++;
|
||||
serverAssert(sleeping_threads <= cserver.cthreads);
|
||||
}
|
||||
@@ -2653,6 +2651,7 @@ void afterSleep(struct aeEventLoop *eventLoop) {
|
||||
Otherwise you may double acquire the GIL and cause deadlocks in the module */
|
||||
if (!ProcessingEventsWhileBlocked) {
|
||||
if (serverTL->modulesEnabledThisAeLoop) moduleAcquireGIL(TRUE /*fServerThread*/);
|
||||
aeThreadOnline();
|
||||
wakeTimeThread();
|
||||
}
|
||||
}
|
||||
@@ -6290,7 +6289,7 @@ int redisFork(int purpose) {
|
||||
openChildInfoPipe();
|
||||
}
|
||||
long long startWriteLock = ustime();
|
||||
g_forkLock->acquireWrite();
|
||||
aeAcquireForkLock();
|
||||
latencyAddSampleIfNeeded("fork-lock",(ustime()-startWriteLock)/1000);
|
||||
if ((childpid = fork()) == 0) {
|
||||
/* Child */
|
||||
@@ -6300,7 +6299,7 @@ int redisFork(int purpose) {
|
||||
closeChildUnusedResourceAfterFork();
|
||||
} else {
|
||||
/* Parent */
|
||||
g_forkLock->releaseWrite();
|
||||
aeReleaseForkLock();
|
||||
g_pserver->stat_total_forks++;
|
||||
g_pserver->stat_fork_time = ustime()-start;
|
||||
g_pserver->stat_fork_rate = (double) zmalloc_used_memory() * 1000000 / g_pserver->stat_fork_time / (1024*1024*1024); /* GB per second. */
|
||||
@@ -6618,7 +6617,9 @@ void OnTerminate()
|
||||
|
||||
void wakeTimeThread() {
|
||||
updateCachedTime();
|
||||
std::lock_guard<std::mutex> lock(time_thread_mutex);
|
||||
aeThreadOffline();
|
||||
std::unique_lock<fastlock> lock(time_thread_lock);
|
||||
aeThreadOnline();
|
||||
if (sleeping_threads >= cserver.cthreads)
|
||||
time_thread_cv.notify_one();
|
||||
sleeping_threads--;
|
||||
@@ -6630,21 +6631,23 @@ void *timeThreadMain(void*) {
|
||||
delay.tv_sec = 0;
|
||||
delay.tv_nsec = 100;
|
||||
int cycle_count = 0;
|
||||
g_forkLock->acquireRead();
|
||||
aeThreadOnline();
|
||||
while (true) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(time_thread_mutex);
|
||||
aeThreadOffline();
|
||||
std::unique_lock<fastlock> lock(time_thread_lock);
|
||||
aeThreadOnline();
|
||||
if (sleeping_threads >= cserver.cthreads) {
|
||||
g_forkLock->releaseRead();
|
||||
aeThreadOffline();
|
||||
time_thread_cv.wait(lock);
|
||||
g_forkLock->acquireRead();
|
||||
aeThreadOnline();
|
||||
cycle_count = 0;
|
||||
}
|
||||
}
|
||||
updateCachedTime();
|
||||
if (cycle_count == MAX_CYCLES_TO_HOLD_FORK_LOCK) {
|
||||
g_forkLock->releaseRead();
|
||||
g_forkLock->acquireRead();
|
||||
aeThreadOffline();
|
||||
aeThreadOnline();
|
||||
cycle_count = 0;
|
||||
}
|
||||
#if defined(__APPLE__)
|
||||
@@ -6654,7 +6657,7 @@ void *timeThreadMain(void*) {
|
||||
#endif
|
||||
cycle_count++;
|
||||
}
|
||||
g_forkLock->releaseRead();
|
||||
aeThreadOffline();
|
||||
}
|
||||
|
||||
void *workerThreadMain(void *parg)
|
||||
@@ -6672,6 +6675,7 @@ void *workerThreadMain(void *parg)
|
||||
}
|
||||
|
||||
moduleAcquireGIL(true); // Normally afterSleep acquires this, but that won't be called on the first run
|
||||
aeThreadOnline();
|
||||
aeEventLoop *el = g_pserver->rgthreadvar[iel].el;
|
||||
try
|
||||
{
|
||||
@@ -6680,6 +6684,7 @@ void *workerThreadMain(void *parg)
|
||||
catch (ShutdownException)
|
||||
{
|
||||
}
|
||||
aeThreadOffline();
|
||||
moduleReleaseGIL(true);
|
||||
serverAssert(!GlobalLocksAcquired());
|
||||
aeDeleteEventLoop(el);
|
||||
@@ -6817,8 +6822,8 @@ int main(int argc, char **argv) {
|
||||
g_pserver->sentinel_mode = checkForSentinelMode(argc,argv);
|
||||
initServerConfig();
|
||||
serverTL = &g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN];
|
||||
aeThreadOnline();
|
||||
aeAcquireLock(); // We own the lock on boot
|
||||
|
||||
ACLInit(); /* The ACL subsystem must be initialized ASAP because the
|
||||
basic networking code and client creation depends on it. */
|
||||
moduleInitModulesSystem();
|
||||
@@ -7048,6 +7053,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
redisSetCpuAffinity(g_pserver->server_cpulist);
|
||||
aeReleaseLock(); //Finally we can dump the lock
|
||||
aeThreadOffline();
|
||||
moduleReleaseGIL(true);
|
||||
|
||||
setOOMScoreAdj(-1);
|
||||
|
||||
@@ -2177,7 +2177,6 @@ typedef struct {
|
||||
|
||||
//extern struct redisServer server;
|
||||
extern redisServer *g_pserver;
|
||||
extern readWriteLock *g_forkLock;
|
||||
extern struct redisServerConst cserver;
|
||||
extern __thread struct redisServerThreadVars *serverTL; // thread local server vars
|
||||
extern struct sharedObjectsStruct shared;
|
||||
|
||||
Reference in new issue
Block a user