Skip to content

Commit f133b78

Browse files
committed
Refactor buffer management in Rayneo_Start and enhance thread safety in Rayneo_Stop
1 parent 5383dc2 commit f133b78

1 file changed

Lines changed: 26 additions & 17 deletions

File tree

src/RayneoApi.cpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -898,30 +898,20 @@ RAYNEO_Result Rayneo_Start(RAYNEO_Context ctx, uint32_t /*serviceFlags*/)
898898
};
899899
size_t inSize = ctx->epInMaxPacket ? ctx->epInMaxPacket : 64;
900900
if (inSize < 64) inSize = 64;
901-
std::vector<uint8_t> *bufferHolder = new std::vector<uint8_t>(inSize); // freed on worker exit
901+
auto bufferHolder = std::make_unique<std::vector<uint8_t>>(inSize); // freed on worker exit
902902
libusb_fill_interrupt_transfer(ctx->inTransfer, ctx->handle, ctx->epIn, bufferHolder->data(), (int)inSize, transferCallback, ctx, 0);
903903
ctx->transferActive.store(true);
904904
ctx->transferDone.store(false);
905905
ctx->transferResubmit.store(true);
906906
int submitRc = libusb_submit_transfer(ctx->inTransfer);
907907
(void)submitRc;
908-
ctx->worker = std::thread([ctx, bufferHolder]
908+
ctx->worker = std::thread([ctx]()
909909
{
910910
while (!ctx->stopWorker.load())
911911
{
912912
timeval tv{0, 100000}; // 100ms
913913
libusb_handle_events_timeout_completed(ctx->usbCtx, &tv, nullptr);
914914
}
915-
ctx->transferResubmit.store(false);
916-
if (ctx->inTransfer && ctx->transferActive.load())
917-
{
918-
for (int i = 0; i < 50 && !ctx->transferDone.load(); ++i)
919-
{
920-
timeval tv{0, 20000};
921-
libusb_handle_events_timeout_completed(ctx->usbCtx, &tv, nullptr);
922-
}
923-
}
924-
delete bufferHolder;
925915
});
926916
}
927917
#endif
@@ -932,20 +922,44 @@ RAYNEO_Result Rayneo_Stop(RAYNEO_Context ctx)
932922
{
933923
if (!ctx)
934924
return RAYNEO_ERR_INVALID_ARG;
925+
926+
// Prevent deadlock if Rayneo_Stop is called from the event callback (which runs on the worker thread)
927+
if (ctx->worker.joinable() && std::this_thread::get_id() == ctx->worker.get_id())
928+
{
929+
ctx->stopIssued.store(true);
930+
ctx->running.store(false);
931+
ctx->stopWorker.store(true);
932+
// We cannot join() ourselves. The worker will exit its loop eventually since stopWorker is true,
933+
// but we can't safely clean up resources here that the worker might still be using.
934+
return RAYNEO_ERR_BUSY;
935+
}
936+
935937
if (ctx->stopIssued.exchange(true))
936938
return RAYNEO_OK;
937939
bool was = ctx->running.exchange(false);
938940
const bool debug = (std::getenv("RAYNEO_DEBUG_SHUTDOWN") != nullptr);
939941
if (was)
940942
{
941943
ctx->stopWorker.store(true);
944+
#ifndef __APPLE__
945+
// Cancel pending transfer to ensure worker loop wakes up immediately
946+
if (ctx->inTransfer && ctx->transferActive.load())
947+
{
948+
libusb_cancel_transfer(ctx->inTransfer);
949+
}
950+
#endif
942951
#ifdef __APPLE__
943952
if (ctx->hidRunLoop)
944953
CFRunLoopWakeUp(ctx->hidRunLoop);
945954
#endif
946955
if (ctx->worker.joinable())
947956
ctx->worker.join();
948957
#ifndef __APPLE__
958+
if (ctx->inTransfer)
959+
{
960+
libusb_free_transfer(ctx->inTransfer);
961+
ctx->inTransfer = nullptr;
962+
}
949963
if (ctx->handle && ctx->interfaceNumber >= 0)
950964
libusb_release_interface(ctx->handle, ctx->interfaceNumber);
951965
if (ctx->handle)
@@ -958,11 +972,6 @@ RAYNEO_Result Rayneo_Stop(RAYNEO_Context ctx)
958972
libusb_exit(ctx->usbCtx);
959973
ctx->usbCtx = nullptr;
960974
}
961-
if (ctx->inTransfer)
962-
{
963-
libusb_free_transfer(ctx->inTransfer);
964-
ctx->inTransfer = nullptr;
965-
}
966975
#else
967976
ctx->macReadyStatus = RAYNEO_OK;
968977
ctx->macDeviceOnline.store(false);

0 commit comments

Comments
 (0)