@@ -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