Skip to content

Commit 6d5597b

Browse files
committed
Avoid multiple concurrent compile/upload operations
Disable Compile/Run buttons as they get press, and reenable only on function exit. The launched upload process has now a 2minutes timeout before being terminated forcefully. 10 second after pressing "Upload" the button comes pressable again, but this time the previous upload command gets killed explicitely
1 parent b99ab40 commit 6d5597b

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

app/src/processing/app/Editor.java

+26-3
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ public boolean test(Sketch sketch) {
146146

147147
private int numTools = 0;
148148

149+
public boolean avoidMultipleOperations = false;
150+
149151
private final EditorToolbar toolbar;
150152
// these menus are shared so that they needn't be rebuilt for all windows
151153
// each time a sketch is created, renamed, or moved.
@@ -198,7 +200,7 @@ public boolean test(Sketch sketch) {
198200
private Runnable stopHandler;
199201
Runnable exportHandler;
200202
private Runnable exportAppHandler;
201-
203+
private Runnable timeoutUploadHandler;
202204

203205
public Editor(Base ibase, File file, int[] storedLocation, int[] defaultLocation, Platform platform) throws Exception {
204206
super("Arduino");
@@ -1648,6 +1650,7 @@ private void resetHandlers() {
16481650
stopHandler = new DefaultStopHandler();
16491651
exportHandler = new DefaultExportHandler();
16501652
exportAppHandler = new DefaultExportAppHandler();
1653+
timeoutUploadHandler = new TimeoutUploadHandler();
16511654
}
16521655

16531656

@@ -1979,6 +1982,7 @@ public void run() {
19791982

19801983
status.unprogress();
19811984
toolbar.deactivateRun();
1985+
avoidMultipleOperations = false;
19821986
}
19831987
}
19841988

@@ -2367,6 +2371,7 @@ synchronized public void handleExport(final boolean usingProgrammer) {
23672371
console.clear();
23682372
status.progress(tr("Uploading to I/O Board..."));
23692373

2374+
new Thread(timeoutUploadHandler).start();
23702375
new Thread(usingProgrammer ? exportAppHandler : exportHandler).start();
23712376
}
23722377

@@ -2406,6 +2411,7 @@ public void run() {
24062411
e.printStackTrace();
24072412
} finally {
24082413
populatePortMenu();
2414+
avoidMultipleOperations = false;
24092415
}
24102416
status.unprogress();
24112417
uploading = false;
@@ -2500,6 +2506,7 @@ public void run() {
25002506
} catch (Exception e) {
25012507
e.printStackTrace();
25022508
} finally {
2509+
avoidMultipleOperations = false;
25032510
populatePortMenu();
25042511
}
25052512
status.unprogress();
@@ -2514,6 +2521,20 @@ public void run() {
25142521
}
25152522
}
25162523

2524+
class TimeoutUploadHandler implements Runnable {
2525+
2526+
public void run() {
2527+
try {
2528+
//10 seconds, than reactivate upload functionality and let the programmer pid being killed
2529+
Thread.sleep(1000 * 10);
2530+
if (uploading) {
2531+
avoidMultipleOperations = false;
2532+
}
2533+
} catch (InterruptedException e) {
2534+
// noop
2535+
}
2536+
}
2537+
}
25172538

25182539
public void handleSerial() {
25192540
if(serialPlotter != null) {
@@ -2558,7 +2579,7 @@ public void handleSerial() {
25582579

25592580
// If currently uploading, disable the monitor (it will be later
25602581
// enabled when done uploading)
2561-
if (uploading) {
2582+
if (uploading || avoidMultipleOperations) {
25622583
try {
25632584
serialMonitor.suspend();
25642585
} catch (Exception e) {
@@ -2582,8 +2603,10 @@ public void handleSerial() {
25822603
}
25832604

25842605
try {
2585-
serialMonitor.open();
25862606
serialMonitor.setVisible(true);
2607+
if (!avoidMultipleOperations) {
2608+
serialMonitor.open();
2609+
}
25872610
success = true;
25882611
} catch (ConnectException e) {
25892612
statusError(tr("Unable to connect: is the sketch using the bridge?"));

app/src/processing/app/EditorToolbar.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,10 @@ public void mousePressed(MouseEvent e) {
341341

342342
switch (sel) {
343343
case RUN:
344-
editor.handleRun(false, editor.presentHandler, editor.runHandler);
344+
if (!editor.avoidMultipleOperations) {
345+
editor.handleRun(false, editor.presentHandler, editor.runHandler);
346+
editor.avoidMultipleOperations = true;
347+
}
345348
break;
346349

347350
// case STOP:
@@ -370,7 +373,11 @@ public void mousePressed(MouseEvent e) {
370373
break;
371374

372375
case EXPORT:
373-
editor.handleExport(e.isShiftDown());
376+
// launch a timeout timer which can reenable to upload button functionality an
377+
if (!editor.avoidMultipleOperations) {
378+
editor.handleExport(e.isShiftDown());
379+
editor.avoidMultipleOperations = true;
380+
}
374381
break;
375382

376383
case SERIAL:

arduino-core/src/cc/arduino/packages/Uploader.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.util.Arrays;
4545
import java.util.Collection;
4646
import java.util.List;
47+
import java.util.concurrent.TimeUnit;
4748

4849
import static processing.app.I18n.tr;
4950

@@ -102,6 +103,9 @@ public String getAuthorizationKey() {
102103
return null;
103104
}
104105

106+
// static field for last executed programmer process ID
107+
static protected Process programmerPid;
108+
105109
protected boolean executeUploadCommand(Collection<String> command) throws Exception {
106110
return executeUploadCommand(command.toArray(new String[command.size()]));
107111
}
@@ -121,11 +125,16 @@ protected boolean executeUploadCommand(String command[]) throws Exception {
121125
System.out.println();
122126
}
123127
Process process = ProcessUtils.exec(command);
128+
programmerPid = process;
124129
new MessageSiphon(process.getInputStream(), this, 100);
125130
new MessageSiphon(process.getErrorStream(), this, 100);
126131

127-
// wait for the process to finish.
128-
result = process.waitFor();
132+
// wait for the process to finish, but not forever
133+
// kill the flasher process after 2 minutes to avoid 100% cpu spinning
134+
if (!process.waitFor(2, TimeUnit.MINUTES)) {
135+
process.destroyForcibly();
136+
}
137+
result = process.exitValue();
129138
} catch (Exception e) {
130139
e.printStackTrace();
131140
}

arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
7878
}
7979
prefs.putAll(targetPlatform.getTool(tool));
8080

81+
if (programmerPid != null && programmerPid.isAlive()) {
82+
// kill the previous programmer
83+
programmerPid.destroyForcibly();
84+
}
85+
8186
// if no protocol is specified for this board, assume it lacks a
8287
// bootloader and upload using the selected programmer.
8388
if (usingProgrammer || prefs.get("upload.protocol") == null) {
@@ -134,7 +139,7 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
134139
// Scanning for available ports seems to open the port or
135140
// otherwise assert DTR, which would cancel the WDT reset if
136141
// it happened within 250 ms. So we wait until the reset should
137-
// have already occured before we start scanning.
142+
// have already occurred before we start scanning.
138143
actualUploadPort = waitForUploadPort(userSelectedUploadPort, before);
139144
}
140145
} catch (SerialException e) {
@@ -213,6 +218,7 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
213218
finalUploadPort = userSelectedUploadPort;
214219
}
215220
BaseNoGui.selectSerialPort(finalUploadPort);
221+
216222
return uploadResult;
217223
}
218224

0 commit comments

Comments
 (0)