Skip to content

Commit c58841f

Browse files
Merge pull request #285 from pioneers/executor_rewrite
[EXECUTOR] Modified executor to place loops on student end
2 parents c02bcc5 + 0e9c15e commit c58841f

File tree

13 files changed

+110
-198
lines changed

13 files changed

+110
-198
lines changed

executor/executor.c

Lines changed: 40 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -195,77 +195,56 @@ static void executor_init(char* student_code) {
195195
* 3: Timed out by executor
196196
* 4: Unable to find the given function in the student code
197197
*/
198-
static uint8_t run_py_function(const char* func_name, struct timespec* timeout, int loop, PyObject* args, PyObject** py_ret) {
198+
static uint8_t run_py_function(const char* func_name, struct timespec* timeout, PyObject* args, PyObject** py_ret) {
199199
uint8_t ret = 0;
200200

201201
// retrieve the Python function from the student code
202202
PyObject* pFunc = PyObject_GetAttrString(pModule, func_name);
203203
PyObject* pValue = NULL;
204+
log_printf(ERROR, "%s", func_name);
204205
if (pFunc && PyCallable_Check(pFunc)) {
205-
struct timespec start, end;
206-
uint64_t time, max_time = 0;
207-
if (timeout != NULL) {
208-
max_time = timeout->tv_sec * 1e9 + timeout->tv_nsec;
206+
pValue = PyObject_CallObject(pFunc, args); // make call to Python function
207+
208+
// Set return value
209+
if (py_ret != NULL) {
210+
Py_XDECREF(*py_ret); // Decrement previous reference, if it exists
211+
*py_ret = pValue;
212+
} else {
213+
Py_XDECREF(pValue);
209214
}
210215

211-
do {
212-
clock_gettime(CLOCK_MONOTONIC, &start);
213-
pValue = PyObject_CallObject(pFunc, args); // make call to Python function
214-
clock_gettime(CLOCK_MONOTONIC, &end);
215-
216-
// if the time the Python function took was greater than max_time, warn that it's taking too long
217-
time = (end.tv_sec - start.tv_sec) * 1e9 + (end.tv_nsec - start.tv_nsec);
218-
if (timeout != NULL && time > max_time) {
219-
log_printf(WARN, "Function %s is taking longer than %lu milliseconds, indicating a loop or sleep in the code. You probably forgot to put a Robot.sleep call into a robot action instead of a regular function.", func_name, (long) (max_time / 1e6));
220-
}
221-
// if the time the Python function took was less than min_time, sleep to slow down execution
222-
if (time < min_time) {
223-
usleep((min_time - time) / 1000); // Need to convert nanoseconds to microseconds
224-
}
225-
226-
// Set return value
227-
if (py_ret != NULL) {
228-
Py_XDECREF(*py_ret); // Decrement previous reference, if it exists
229-
*py_ret = pValue;
216+
// catch execution error
217+
if (pValue == NULL) {
218+
if (!PyErr_ExceptionMatches(PyExc_TimeoutError)) {
219+
PyErr_Print();
220+
log_printf(ERROR, "Python function %s call failed", func_name);
221+
ret = 2;
230222
} else {
231-
Py_XDECREF(pValue);
223+
ret = 3; // Timed out by parent process
232224
}
233-
234-
// catch execution error
235-
if (pValue == NULL) {
225+
} else if (mode == AUTO || mode == TELEOP) {
226+
// Need to check if error occurred in action thread
227+
PyObject* event = PyObject_GetAttrString(pRobot, "error_event");
228+
if (event == NULL) {
229+
PyErr_Print();
230+
log_printf(ERROR, "Could not get error_event from Robot instance");
231+
exit(2);
232+
}
233+
PyObject* event_set = PyObject_CallMethod(event, "is_set", NULL);
234+
if (event_set == NULL) {
236235
if (!PyErr_ExceptionMatches(PyExc_TimeoutError)) {
237236
PyErr_Print();
238-
log_printf(ERROR, "Python function %s call failed", func_name);
239-
ret = 2;
237+
log_printf(DEBUG, "Could not get if error is set from error_event");
238+
exit(2);
240239
} else {
241240
ret = 3; // Timed out by parent process
242241
}
243-
break;
244-
} else if (mode == AUTO || mode == TELEOP) {
245-
// Need to check if error occurred in action thread
246-
PyObject* event = PyObject_GetAttrString(pRobot, "error_event");
247-
if (event == NULL) {
248-
PyErr_Print();
249-
log_printf(ERROR, "Could not get error_event from Robot instance");
250-
exit(2);
251-
}
252-
PyObject* event_set = PyObject_CallMethod(event, "is_set", NULL);
253-
if (event_set == NULL) {
254-
if (!PyErr_ExceptionMatches(PyExc_TimeoutError)) {
255-
PyErr_Print();
256-
log_printf(DEBUG, "Could not get if error is set from error_event");
257-
exit(2);
258-
} else {
259-
ret = 3; // Timed out by parent process
260-
}
261-
break;
262-
} else if (PyObject_IsTrue(event_set) == 1) {
263-
log_printf(ERROR, "Stopping %s due to error in action", func_name);
264-
ret = 1;
265-
break;
266-
}
242+
} else if (PyObject_IsTrue(event_set) == 1) {
243+
log_printf(ERROR, "Stopping %s due to error in action", func_name);
244+
ret = 1;
267245
}
268-
} while (loop);
246+
}
247+
269248
Py_DECREF(pFunc);
270249
} else {
271250
if (PyErr_Occurred()) {
@@ -278,32 +257,6 @@ static uint8_t run_py_function(const char* func_name, struct timespec* timeout,
278257
}
279258

280259

281-
/**
282-
* Begins the given game mode and calls setup and main appropriately. Will run main forever.
283-
*
284-
* Behavior: This is a blocking function and will block the calling thread forever.
285-
* This should only be run as a separate thread.
286-
*
287-
* Inputs:
288-
* args: string of the mode to start running
289-
*/
290-
static void run_mode(robot_desc_val_t mode) {
291-
// Set up the arguments to the threads that will run the setup and main threads
292-
char* mode_str = get_mode_str(mode);
293-
char setup_str[20], main_str[20];
294-
sprintf(setup_str, "%s_setup", mode_str);
295-
sprintf(main_str, "%s_main", mode_str);
296-
297-
int err = run_py_function(setup_str, &setup_time, 0, NULL, NULL); // Run setup function once
298-
if (err == 0) {
299-
err = run_py_function(main_str, &main_interval, 1, NULL, NULL); // Run main function on loop
300-
} else {
301-
log_printf(WARN, "Won't run %s due to error %d in %s", main_str, err, setup_str);
302-
}
303-
return;
304-
}
305-
306-
307260
/**
308261
* Handler for killing the child mode subprocess
309262
*/
@@ -361,7 +314,12 @@ static pid_t start_mode_subprocess(char* student_code) {
361314
signal(SIGINT, SIG_IGN); // Disable Ctrl+C for child process
362315
executor_init(student_code);
363316
signal(SIGTERM, python_exit_handler); // Set handler for killing subprocess
364-
run_mode(mode);
317+
318+
char* mode_str = get_mode_str(mode);
319+
int err = run_py_function(mode_str, &main_interval, NULL, NULL); // Run main function
320+
if (err) {
321+
log_printf(WARN, "NEED TO EDIT STATEMENT"); // "Problem Child"
322+
}
365323
exit(0);
366324
return pid; // Never reach this statement due to exit, needed to fix compiler warning
367325
} else {

executor/studentcode.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
1+
def autonomous():
2+
print("Autonomous has begun!")
13

2-
def autonomous_setup():
3-
print('Autonomous setup has begun!')
4-
5-
def autonomous_main():
6-
pass
7-
8-
def teleop_setup():
9-
print('Teleop setup has begun!')
10-
11-
def teleop_main():
12-
pass
4+
def teleop():
5+
print("Teleop has begun!")

systemd/runtime_update.service

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ Description=Update process for Runtime
33

44
[Service]
55
Type=oneshot
6-
User=pi
7-
WorkingDirectory=/home/pi/runtime
8-
ExecStart=/home/pi/runtime/scripts/update.sh
6+
User=ubuntu
7+
WorkingDirectory=/home/ubuntu/runtime
8+
ExecStart=/home/ubuntu/runtime/scripts/update.sh
99
KillSignal=SIGINT
1010

1111
[Install]

tests/integration/tc_71_2.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
char check_output_6[] =
11-
" File \"/home/runner/work/runtime/runtime/tests/student_code/executor_sanity.py\", line 25, in teleop_main\n"
11+
" File \"/home/runner/work/runtime/runtime/tests/student_code/executor_sanity.py\", line 19, in teleop\n"
1212
" oops = 1 / 0\n"
1313
" ~~^~~\n"
1414
"ZeroDivisionError: division by zero\n";
@@ -37,7 +37,7 @@ int main() {
3737
send_run_mode(SHEPHERD, TELEOP);
3838
add_ordered_string_output("Traceback (most recent call last):\n");
3939
add_ordered_string_output(check_output_6);
40-
add_ordered_string_output("Python function teleop_main call failed\n");
40+
add_ordered_string_output("Python function teleop call failed\n");
4141
check_run_mode(TELEOP);
4242

4343
send_run_mode(DAWN, IDLE);

tests/student_code/executor_sanity.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,12 @@ def constant_print(msg):
88
print(f"{msg} printing again")
99
time.sleep(2)
1010

11-
def autonomous_setup():
11+
def autonomous():
1212
print('Autonomous setup has begun!')
1313
print(f"Starting position: {Robot.start_pos}")
1414
Robot.run(constant_print, "autonomous")
1515

16-
def autonomous_main():
17-
pass
18-
1916
# This teleop code generates a DivisionByZero Python error
2017

21-
def teleop_setup():
22-
pass
23-
24-
def teleop_main():
18+
def teleop():
2519
oops = 1 / 0
Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11

22
simple_device = "62_20"
33

4-
def autonomous_setup():
4+
def autonomous():
55
pass
66

7-
def autonomous_main():
8-
pass
9-
10-
def teleop_setup():
11-
pass
12-
13-
def teleop_main():
14-
if Keyboard.get_value('a'):
15-
Robot.set_value(simple_device, "MY_INT", 123454321)
16-
elif Keyboard.get_value('y'):
17-
print(Robot.get_value(simple_device, "MY_INT"))
18-
Robot.sleep(.45)
7+
def teleop():
8+
while True:
9+
if Keyboard.get_value('a'):
10+
Robot.set_value(simple_device, "MY_INT", 123454321)
11+
elif Keyboard.get_value('y'):
12+
print(Robot.get_value(simple_device, "MY_INT"))
13+
Robot.sleep(.45)

tests/student_code/net_handler_integration.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@ def modify_my_int():
2020
Robot.set_value(SIMPLE_DEV, "MY_INT", Robot.get_value(SIMPLE_DEV, "MY_INT") - 1)
2121
Robot.sleep(1)
2222

23-
def teleop_setup():
23+
def teleop():
2424
print("Teleop setup has begun!")
2525
Robot.run(print_if_button_a)
2626
Robot.run(modify_my_int)
27-
28-
def teleop_main():
2927
global i
30-
if i < 3 and Gamepad.get_value('joystick_left_x') != 0.0:
31-
print("Left joystick moved in x direction!")
32-
i += 1
28+
while True:
29+
if i < 3 and Gamepad.get_value('joystick_left_x') != 0.0:
30+
print("Left joystick moved in x direction!")
31+
i += 1

tests/student_code/runtime_latency.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,10 @@
22

33
time_dev = '60_123'
44

5-
def autonomous_setup():
5+
def autonomous():
66
pass
77

8-
def autonomous_main():
9-
pass
10-
11-
def teleop_setup():
12-
pass
13-
14-
def teleop_main():
15-
if Gamepad.get_value('button_a'):
16-
Robot.set_value(time_dev, "GET_TIME", True)
8+
def teleop():
9+
while True:
10+
if Gamepad.get_value('button_a'):
11+
Robot.set_value(time_dev, "GET_TIME", True)

tests/student_code/sanity_write.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,14 @@ def constant_write():
1515
Robot.set_value(GeneralTestDevice, "RED_INT", int_val)
1616
Robot.set_value(GeneralTestDevice, "ORANGE_FLOAT", float_val)
1717
Robot.set_value(GeneralTestDevice, "YELLOW_BOOL", bool_val)
18-
int_val += 2;
18+
int_val += 2
1919
float_val += 3.14
2020
bool_val = not bool_val
2121

22-
def autonomous_setup():
22+
def autonomous():
2323
Robot.run(constant_write)
24+
while True:
25+
pass
2426

25-
def autonomous_main():
26-
pass
27-
28-
def teleop_setup():
29-
pass
30-
31-
def teleop_main():
27+
def teleop():
3228
pass

tests/student_code/sound_device.py

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Student code that plays pitches from keyboard inputs
2+
# Commented out print_buttons and play_notes functions as they are not run
23
import time
34

45
SOUND = '59_1'
@@ -23,8 +24,8 @@
2324

2425
################################## AUTONOMOUS ##################################
2526

26-
def autonomous_setup():
27-
print("Now executing AUTONOMOUS SETUP")
27+
def autonomous():
28+
print("Now executing AUTONOMOUS")
2829
# Write pitches
2930
for note in NOTES:
3031
if (note == ' '):
@@ -35,35 +36,30 @@ def autonomous_setup():
3536
Robot.set_value(SOUND, "PITCH", MAP[note])
3637
time.sleep(NOTE_DURATION)
3738

38-
def autonomous_main():
39-
pass
40-
4139
#################################### TELEOP ####################################
4240

43-
def teleop_setup():
44-
print("Now executing TELEOP SETUP")
41+
def teleop():
42+
print("Now executing TELEOP")
4543
# Robot.run(print_button)
4644
# Robot.run(play_notes)
47-
pass
48-
49-
def teleop_main():
50-
if Gamepad.get_value('button_a'):
51-
Robot.set_value(SOUND, "PITCH", MAP['C'])
52-
print("Wrote Button A: Pitch C")
53-
time.sleep(NOTE_DURATION);
54-
if Gamepad.get_value('button_b'):
55-
Robot.set_value(SOUND, "PITCH", MAP['B'])
56-
print("Wrote Button B: Pitch B")
57-
time.sleep(NOTE_DURATION);
45+
while True:
46+
if Gamepad.get_value('button_a'):
47+
Robot.set_value(SOUND, "PITCH", MAP['C'])
48+
print("Wrote Button A: Pitch C")
49+
time.sleep(NOTE_DURATION);
50+
if Gamepad.get_value('button_b'):
51+
Robot.set_value(SOUND, "PITCH", MAP['B'])
52+
print("Wrote Button B: Pitch B")
53+
time.sleep(NOTE_DURATION);
5854

5955
################################### THREADS ####################################
6056

61-
def print_button():
62-
while (1):
63-
if Gamepad.get_value('button_a'):
64-
print("BUTTON A IS PRESSED")
65-
if Gamepad.get_value('button_b'):
66-
print("BUTTON B IS PRESSED")
57+
# def print_button():
58+
# while (1):
59+
# if Gamepad.get_value('button_a'):
60+
# print("BUTTON A IS PRESSED")
61+
# if Gamepad.get_value('button_b'):
62+
# print("BUTTON B IS PRESSED")
6763

6864
# def play_notes():
6965
# while (1):

0 commit comments

Comments
 (0)