Commit b55a98946f9837e22e8a2cdad22147f1c5ab822e
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) |