upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 17:42:24 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 17:42:24 +0000
commitb8a976f4870ba5dfc7a6af1ea09c9277b71d686c (patch)
tree24bc580af6e1616fd1854ebc86f700c508e62a43
parent0a8c445742ce871c6b9352bf406d2232a6fd3134 (diff)
gui: check the two thread spawns the GUI target still leaves unguarded
gui.cpp is not in NODE_OBJS, so bitflash-node never sees it -- but it is in GUI_OBJS and `all: bitflash` is the default target, so this is what an operator who runs the windowed build is running. Two spawns there were still unchecked. Enabling pool mode from the options dialog set gPoolServerRunning = true and then called _beginthread without looking at the result, so a refused spawn left the operator with a pool that reports itself running, no RPC server for miners to reach, and nothing in the log. The flag latches, so the branch is never retried either. The restore dialog called std::thread(RestoreThread).detach() bare, which on a refused spawn is an uncaught std::system_error and takes the window down -- the same failure issue #18 was about, in the same tree, one target over. The busy flag stays where it was, set before the spawn and rolled back in the catch. It cannot move after the spawn: RestoreThread clears it itself on the way out, and a restore that finishes quickly would have its `false` overwritten by ours, leaving the dialog greyed out over a search that is not running. Verified by type-checking gui.cpp under the Makefile's exact flags against a stub GLFW/GL header, since this host has neither. That is a syntax and type check, not a link: gui.cpp reaches GLFW through 13 functions and three GL calls, all declared with their real signatures, but the GUI target has not been built here.
-rw-r--r--src/gui.cpp34
1 files changed, 30 insertions, 4 deletions
diff --git a/src/gui.cpp b/src/gui.cpp
index 8dcb854..9b3802b 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -15,6 +15,7 @@
15#include <atomic> 15#include <atomic>
16#include <mutex> 16#include <mutex>
17#include <thread> 17#include <thread>
18#include <system_error>
18#include "bip32.h" 19#include "bip32.h"
19#include "walletcmd.h" 20#include "walletcmd.h"
20#include "font_roboto.h" 21#include "font_roboto.h"
@@ -910,8 +911,16 @@ static void DrawOptionsDialog()
910 911
911 if (nMineMode == MINE_OPERATOR) { 912 if (nMineMode == MINE_OPERATOR) {
912 if (!gPoolServerRunning) { 913 if (!gPoolServerRunning) {
913 gPoolServerRunning = true; 914 // Claim the server is up only once it is. The flag used to
914 _beginthread(ThreadRPCServer, 0, NULL); 915 // be set first and the result never looked at, so a refused
916 // spawn left an operator with a pool that reports itself
917 // running, no RPC server for miners to reach, and nothing
918 // anywhere saying why. The flag also latches: with it set,
919 // this branch is never retried.
920 if (_beginthread(ThreadRPCServer, 0, NULL) == (uintptr_t)-1)
921 printf("Error: _beginthread(ThreadRPCServer) failed -- pool server not started\n");
922 else
923 gPoolServerRunning = true;
915 } else if (!gPoolRunning) { 924 } else if (!gPoolRunning) {
916 gPoolRunning = true; 925 gPoolRunning = true;
917 } 926 }
@@ -1124,11 +1133,28 @@ static void DrawRestorePhraseDialog()
1124 } 1133 }
1125 g_restoreDerived.store(0); 1134 g_restoreDerived.store(0);
1126 g_restoreRecovered.store(0); 1135 g_restoreRecovered.store(0);
1136 // Set before the spawn, not after: RestoreThread clears this
1137 // flag itself when it finishes, and a short restore can beat
1138 // us back here and have its `false` overwritten, leaving the
1139 // dialog disabled forever.
1127 g_restoreRunning.store(true); 1140 g_restoreRunning.store(true);
1128 // On its own thread: a restore walks the whole chain once per 1141 // On its own thread: a restore walks the whole chain once per
1129 // batch and would otherwise freeze the window for as long as it 1142 // batch and would otherwise freeze the window for as long as it
1130 // takes. 1143 // takes. A refused spawn is one restore that does not happen,
1131 std::thread(RestoreThread, std::string(g_restoreInput)).detach(); 1144 // not a reason to take the window down with an uncaught
1145 // std::system_error -- and the flag has to come back off, or
1146 // the dialog sits greyed out reporting a search nobody is
1147 // running.
1148 try
1149 {
1150 std::thread(RestoreThread, std::string(g_restoreInput)).detach();
1151 }
1152 catch (const std::system_error& e)
1153 {
1154 g_restoreRunning.store(false);
1155 std::lock_guard<std::mutex> lock(g_restoreResultMutex);
1156 g_restoreResult = std::string("Could not start the search: ") + e.what();
1157 }
1132 } 1158 }
1133 } 1159 }
1134 if (fBusy) 1160 if (fBusy)