@@ -47,7 +47,7 @@ type ParallelGuessGenerator struct {
4747 startTime time.Time
4848
4949 // from previous session when resuming with -l (accumulated stats)
50- prevRunningTime int64
50+ prevRunningTime int64
5151 originalFirstStarted string // RFC3339, preserved when resuming
5252}
5353
@@ -97,11 +97,13 @@ func NewParallelGuessGeneratorWithQueueAndRestore(grammar pcfg.Grammar, base []p
9797
9898// generates guesses using all CPU cores
9999func (g * ParallelGuessGenerator ) RunParallel (limit int64 ) (int64 , error ) {
100- return g .runParallelWithCtx (context .Background (), limit , nil )
100+ ctx , cancel := context .WithCancel (context .Background ())
101+ defer cancel ()
102+ return g .runParallelWithCtx (ctx , limit , cancel )
101103}
102104
103- // runs with session save/load. On Ctrl+C, saves and exits gracefully.
104- // Save runs on every exit path: normal completion, signal (SIGINT/SIGTERM), or panic.
105+ // runs with session save/load, on Ctrl+C, saves and exits gracefully
106+ // save runs on every exit path: normal completion, signal (SIGINT/SIGTERM), or panic
105107func (g * ParallelGuessGenerator ) RunParallelWithSession (limit int64 , savePath , ruleName , ruleUUID string , skipBrute , skipCase bool ) (int64 , error ) {
106108 // Ignore SIGPIPE so piping to pv, head, etc. doesn't kill us before save on Ctrl+C
107109 signal .Ignore (syscall .SIGPIPE )
@@ -116,7 +118,7 @@ func (g *ParallelGuessGenerator) RunParallelWithSession(limit int64, savePath, r
116118 cancel ()
117119 }()
118120
119- // Always save on exit: normal, signal, or panic. Works for first run and -l (load).
121+ // always save on exit: normal, signal, or panic. Works for first run and -l (load)
120122 defer func () {
121123 currentRunTime := int64 (time .Since (g .startTime ).Seconds ())
122124 cfg := & SessionConfig {
@@ -137,7 +139,8 @@ func (g *ParallelGuessGenerator) RunParallelWithSession(limit int64, savePath, r
137139 return g .runParallelWithCtx (ctx , limit , cancel )
138140}
139141
140- func (g * ParallelGuessGenerator ) runParallelWithCtx (ctx context.Context , limit int64 , cancelOnPipe func ()) (int64 , error ) {
142+ // stops the popper and workers (SIGINT/SIGTERM, broken pipe, or -n limit reached)
143+ func (g * ParallelGuessGenerator ) runParallelWithCtx (ctx context.Context , limit int64 , cancelRun func ()) (int64 , error ) {
141144 numWorkers := runtime .NumCPU ()
142145 if numWorkers < 1 {
143146 numWorkers = 1
@@ -154,9 +157,9 @@ func (g *ParallelGuessGenerator) runParallelWithCtx(ctx context.Context, limit i
154157 defer wg .Done ()
155158 defer writer .Flush ()
156159 for buf := range g .outputChan {
157- if _ , err := writer .Write (buf ); err != nil && cancelOnPipe != nil {
160+ if _ , err := writer .Write (buf ); err != nil && cancelRun != nil {
158161 // broken pipe, reader exited - cancel to trigger save
159- cancelOnPipe ()
162+ cancelRun ()
160163 }
161164 }
162165 }()
@@ -210,6 +213,10 @@ func (g *ParallelGuessGenerator) runParallelWithCtx(ctx context.Context, limit i
210213 if limit > 0 {
211214 v := remaining .Add (- 1 )
212215 if v < 0 {
216+ // stop popper/workers so batches flush; otherwise buffer only drains at queue end or SIGINT
217+ if cancelRun != nil {
218+ cancelRun ()
219+ }
213220 return nil
214221 }
215222 }
0 commit comments