Skip to content

Commit 3f07b8a

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 f027003 commit 3f07b8a

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

Diff for: app/src/processing/app/Editor.java

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

144144
private int numTools = 0;
145145

146+
public boolean avoidMultipleOperations = false;
147+
146148
private final EditorToolbar toolbar;
147149
// these menus are shared so that they needn't be rebuilt for all windows
148150
// each time a sketch is created, renamed, or moved.
@@ -195,7 +197,7 @@ public boolean test(Sketch sketch) {
195197
private Runnable stopHandler;
196198
Runnable exportHandler;
197199
private Runnable exportAppHandler;
198-
200+
private Runnable timeoutUploadHandler;
199201

200202
public Editor(Base ibase, File file, int[] storedLocation, int[] defaultLocation, Platform platform) throws Exception {
201203
super("Arduino");
@@ -1677,6 +1679,7 @@ private void resetHandlers() {
16771679
stopHandler = new DefaultStopHandler();
16781680
exportHandler = new DefaultExportHandler();
16791681
exportAppHandler = new DefaultExportAppHandler();
1682+
timeoutUploadHandler = new TimeoutUploadHandler();
16801683
}
16811684

16821685

@@ -2008,6 +2011,7 @@ public void run() {
20082011

20092012
status.unprogress();
20102013
toolbar.deactivateRun();
2014+
avoidMultipleOperations = false;
20112015
}
20122016
}
20132017

@@ -2396,6 +2400,7 @@ synchronized public void handleExport(final boolean usingProgrammer) {
23962400
console.clear();
23972401
status.progress(tr("Uploading to I/O Board..."));
23982402

2403+
new Thread(timeoutUploadHandler).start();
23992404
new Thread(usingProgrammer ? exportAppHandler : exportHandler).start();
24002405
}
24012406

@@ -2435,6 +2440,7 @@ public void run() {
24352440
e.printStackTrace();
24362441
} finally {
24372442
populatePortMenu();
2443+
avoidMultipleOperations = false;
24382444
}
24392445
status.unprogress();
24402446
uploading = false;
@@ -2529,6 +2535,7 @@ public void run() {
25292535
} catch (Exception e) {
25302536
e.printStackTrace();
25312537
} finally {
2538+
avoidMultipleOperations = false;
25322539
populatePortMenu();
25332540
}
25342541
status.unprogress();
@@ -2543,6 +2550,20 @@ public void run() {
25432550
}
25442551
}
25452552

2553+
class TimeoutUploadHandler implements Runnable {
2554+
2555+
public void run() {
2556+
try {
2557+
//10 seconds, than reactivate upload functionality and let the programmer pid being killed
2558+
Thread.sleep(1000 * 10);
2559+
if (uploading) {
2560+
avoidMultipleOperations = false;
2561+
}
2562+
} catch (InterruptedException e) {
2563+
// noop
2564+
}
2565+
}
2566+
}
25462567

25472568
public void handleSerial() {
25482569
if(serialPlotter != null) {
@@ -2587,7 +2608,7 @@ public void handleSerial() {
25872608

25882609
// If currently uploading, disable the monitor (it will be later
25892610
// enabled when done uploading)
2590-
if (uploading) {
2611+
if (uploading || avoidMultipleOperations) {
25912612
try {
25922613
serialMonitor.suspend();
25932614
} catch (Exception e) {
@@ -2611,8 +2632,10 @@ public void handleSerial() {
26112632
}
26122633

26132634
try {
2614-
serialMonitor.open();
26152635
serialMonitor.setVisible(true);
2636+
if (!avoidMultipleOperations) {
2637+
serialMonitor.open();
2638+
}
26162639
success = true;
26172640
} catch (ConnectException e) {
26182641
statusError(tr("Unable to connect: is the sketch using the bridge?"));

Diff for: app/src/processing/app/EditorToolbar.java

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

338338
switch (sel) {
339339
case RUN:
340-
editor.handleRun(false, editor.presentHandler, editor.runHandler);
340+
if (!editor.avoidMultipleOperations) {
341+
editor.handleRun(false, editor.presentHandler, editor.runHandler);
342+
editor.avoidMultipleOperations = true;
343+
}
341344
break;
342345

343346
// case STOP:
@@ -366,7 +369,11 @@ public void mousePressed(MouseEvent e) {
366369
break;
367370

368371
case EXPORT:
369-
editor.handleExport(e.isShiftDown());
372+
// launch a timeout timer which can reenable to upload button functionality an
373+
if (!editor.avoidMultipleOperations) {
374+
editor.handleExport(e.isShiftDown());
375+
editor.avoidMultipleOperations = true;
376+
}
370377
break;
371378

372379
case SERIAL:

Diff for: 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
}

Diff for: 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)