Fix more locking deadlocks
Former-commit-id: 3081b6f98b5e7a9f3ef7cfe040236070398b081c
This commit is contained in:
parent
8f1e7d9d5b
commit
e78ed8cc64
@ -706,7 +706,7 @@ void _serverAssertPrintClientInfo(const client *c) {
|
||||
|
||||
bugReportStart();
|
||||
serverLog(LL_WARNING,"=== ASSERTION FAILED CLIENT CONTEXT ===");
|
||||
serverLog(LL_WARNING,"client->flags = %d", c->flags);
|
||||
serverLog(LL_WARNING,"client->flags = %d", static_cast<int>(c->flags));
|
||||
serverLog(LL_WARNING,"client->fd = %d", c->fd);
|
||||
serverLog(LL_WARNING,"client->argc = %d", c->argc);
|
||||
for (j=0; j < c->argc; j++) {
|
||||
|
@ -1476,15 +1476,7 @@ int writeToClient(int fd, client *c, int handler_installed) {
|
||||
serverLog(LL_VERBOSE,
|
||||
"Error writing to client: %s", strerror(errno));
|
||||
lock.unlock();
|
||||
if (aeTryAcquireLock(true /*fWeak*/))
|
||||
{
|
||||
freeClient(c);
|
||||
aeReleaseLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
freeClientAsync(c);
|
||||
}
|
||||
|
||||
return C_ERR;
|
||||
}
|
||||
@ -1503,15 +1495,7 @@ int writeToClient(int fd, client *c, int handler_installed) {
|
||||
/* Close connection after entire reply has been sent. */
|
||||
if (c->flags & CLIENT_CLOSE_AFTER_REPLY) {
|
||||
lock.unlock();
|
||||
if (aeTryAcquireLock(true /*fWeak*/))
|
||||
{
|
||||
freeClient(c);
|
||||
aeReleaseLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
freeClientAsync(c);
|
||||
}
|
||||
return C_ERR;
|
||||
}
|
||||
}
|
||||
@ -1524,7 +1508,14 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
client *c = (client*)privdata;
|
||||
|
||||
serverAssert(ielFromEventLoop(el) == c->iel);
|
||||
writeToClient(fd,c,1);
|
||||
if (writeToClient(fd,c,1) == C_ERR)
|
||||
{
|
||||
AeLocker ae;
|
||||
c->lock.lock();
|
||||
ae.arm(c);
|
||||
if (c->flags & CLIENT_CLOSE_ASAP)
|
||||
freeClient(c);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessPendingAsyncWrites()
|
||||
@ -1591,27 +1582,6 @@ int handleClientsWithPendingWrites(int iel) {
|
||||
int processed = (int)vec.size();
|
||||
serverAssert(iel == (serverTL - g_pserver->rgthreadvar));
|
||||
|
||||
while(!vec.empty()) {
|
||||
client *c = vec.back();
|
||||
std::unique_lock<decltype(c->lock)> lock(c->lock);
|
||||
|
||||
c->flags &= ~CLIENT_PENDING_WRITE;
|
||||
vec.pop_back();
|
||||
AssertCorrectThread(c);
|
||||
|
||||
/* If a client is protected, don't do anything,
|
||||
* that may trigger write error or recreate handler. */
|
||||
if (c->flags & CLIENT_PROTECTED) continue;
|
||||
|
||||
/* Try to write buffers to the client socket. */
|
||||
if (writeToClient(c->fd,c,0) == C_ERR) {
|
||||
lock.release(); // client is free'd
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If after the synchronous writes above we still have data to
|
||||
* output to the client, we need to install the writable handler. */
|
||||
if (clientHasPendingReplies(c)) {
|
||||
int ae_flags = AE_WRITABLE|AE_WRITE_THREADSAFE;
|
||||
/* For the fsync=always policy, we want that a given FD is never
|
||||
* served for reading and writing in the same event loop iteration,
|
||||
@ -1624,6 +1594,34 @@ int handleClientsWithPendingWrites(int iel) {
|
||||
ae_flags |= AE_BARRIER;
|
||||
}
|
||||
|
||||
while(!vec.empty()) {
|
||||
client *c = vec.back();
|
||||
AssertCorrectThread(c);
|
||||
|
||||
c->flags &= ~CLIENT_PENDING_WRITE;
|
||||
vec.pop_back();
|
||||
|
||||
/* If a client is protected, don't do anything,
|
||||
* that may trigger write error or recreate handler. */
|
||||
if (c->flags & CLIENT_PROTECTED) continue;
|
||||
|
||||
std::unique_lock<decltype(c->lock)> lock(c->lock);
|
||||
|
||||
/* Try to write buffers to the client socket. */
|
||||
if (writeToClient(c->fd,c,0) == C_ERR) {
|
||||
if (c->flags & CLIENT_CLOSE_ASAP)
|
||||
{
|
||||
c->lock.lock();
|
||||
AeLocker ae;
|
||||
ae.arm(c);
|
||||
freeClient(c); // writeToClient will only async close, but there's no need to wait
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If after the synchronous writes above we still have data to
|
||||
* output to the client, we need to install the writable handler. */
|
||||
if (clientHasPendingReplies(c)) {
|
||||
if (aeCreateFileEvent(g_pserver->rgthreadvar[c->iel].el, c->fd, ae_flags, sendReplyToClient, c) == AE_ERR)
|
||||
freeClientAsync(c);
|
||||
}
|
||||
|
@ -921,7 +921,7 @@ typedef struct client {
|
||||
time_t ctime; /* Client creation time. */
|
||||
time_t lastinteraction; /* Time of the last interaction, used for timeout */
|
||||
time_t obuf_soft_limit_reached_time;
|
||||
int flags; /* Client flags: CLIENT_* macros. */
|
||||
std::atomic<int> flags; /* Client flags: CLIENT_* macros. */
|
||||
int fPendingAsyncWrite; /* NOTE: Not a flag because it is written to outside of the client lock (locked by the global lock instead) */
|
||||
int authenticated; /* Needed when the default user requires auth. */
|
||||
int replstate; /* Replication state if this is a slave. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user