Commit b55a98946f9837e22e8a2cdad22147f1c5ab822e

Authored by Wiebe Cazemier
1 parent 940d7edc

Fix readiness race condition

Showing 1 changed file with 13 additions and 9 deletions
client.cpp
@@ -354,17 +354,16 @@ void Client::setReadyForWriting(bool val) @@ -354,17 +354,16 @@ void Client::setReadyForWriting(bool val)
354 if (ioWrapper.getSslReadWantsWrite()) 354 if (ioWrapper.getSslReadWantsWrite())
355 val = true; 355 val = true;
356 356
  357 + // This looks a bit like a race condition, but all calls to this method should be under lock of writeBufMutex, so it should be OK.
357 if (val == this->readyForWriting) 358 if (val == this->readyForWriting)
358 return; 359 return;
359 360
360 readyForWriting = val; 361 readyForWriting = val;
  362 +
361 struct epoll_event ev; 363 struct epoll_event ev;
362 memset(&ev, 0, sizeof (struct epoll_event)); 364 memset(&ev, 0, sizeof (struct epoll_event));
363 ev.data.fd = fd; 365 ev.data.fd = fd;
364 - if (readyForReading)  
365 - ev.events |= EPOLLIN;  
366 - if (readyForWriting)  
367 - ev.events |= EPOLLOUT; 366 + ev.events = readyForReading*EPOLLIN | readyForWriting*EPOLLOUT;
368 check<std::runtime_error>(epoll_ctl(threadData->epollfd, EPOLL_CTL_MOD, fd, &ev)); 367 check<std::runtime_error>(epoll_ctl(threadData->epollfd, EPOLL_CTL_MOD, fd, &ev));
369 } 368 }
370 369
@@ -378,18 +377,23 @@ void Client::setReadyForReading(bool val) @@ -378,18 +377,23 @@ void Client::setReadyForReading(bool val)
378 if (disconnecting) 377 if (disconnecting)
379 return; 378 return;
380 379
  380 + // This looks a bit like a race condition, but all calls to this method are from a threads's event loop, so we should be OK.
381 if (val == this->readyForReading) 381 if (val == this->readyForReading)
382 return; 382 return;
383 383
384 readyForReading = val; 384 readyForReading = val;
  385 +
385 struct epoll_event ev; 386 struct epoll_event ev;
386 memset(&ev, 0, sizeof (struct epoll_event)); 387 memset(&ev, 0, sizeof (struct epoll_event));
387 ev.data.fd = fd; 388 ev.data.fd = fd;
388 - if (readyForReading)  
389 - ev.events |= EPOLLIN;  
390 - if (readyForWriting)  
391 - ev.events |= EPOLLOUT;  
392 - check<std::runtime_error>(epoll_ctl(threadData->epollfd, EPOLL_CTL_MOD, fd, &ev)); 389 +
  390 + {
  391 + // Because setReadyForWriting is always called onder writeBufMutex, this prevents readiness race conditions.
  392 + std::lock_guard<std::mutex> locker(writeBufMutex);
  393 +
  394 + ev.events = readyForReading*EPOLLIN | readyForWriting*EPOLLOUT;
  395 + check<std::runtime_error>(epoll_ctl(threadData->epollfd, EPOLL_CTL_MOD, fd, &ev));
  396 + }
393 } 397 }
394 398
395 bool Client::bufferToMqttPackets(std::vector<MqttPacket> &packetQueueIn, std::shared_ptr<Client> &sender) 399 bool Client::bufferToMqttPackets(std::vector<MqttPacket> &packetQueueIn, std::shared_ptr<Client> &sender)