Skip to content

Commit

Permalink
Documentation, signal names, reported time in ms
Browse files Browse the repository at this point in the history
  • Loading branch information
Brikaa committed Aug 31, 2024
1 parent 2e00325 commit 09ff4ca
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 90 deletions.
47 changes: 4 additions & 43 deletions api/src/api/v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,9 @@ const events = require('events');
const runtime = require('../runtime');
const { Job } = require('../job');
const package = require('../package');
const globals = require('../globals');
const logger = require('logplease').create('api/v2');

const SIGNALS = [
'SIGABRT',
'SIGALRM',
'SIGBUS',
'SIGCHLD',
'SIGCLD',
'SIGCONT',
'SIGEMT',
'SIGFPE',
'SIGHUP',
'SIGILL',
'SIGINFO',
'SIGINT',
'SIGIO',
'SIGIOT',
'SIGKILL',
'SIGLOST',
'SIGPIPE',
'SIGPOLL',
'SIGPROF',
'SIGPWR',
'SIGQUIT',
'SIGSEGV',
'SIGSTKFLT',
'SIGSTOP',
'SIGTSTP',
'SIGSYS',
'SIGTERM',
'SIGTRAP',
'SIGTTIN',
'SIGTTOU',
'SIGUNUSED',
'SIGURG',
'SIGUSR1',
'SIGUSR2',
'SIGVTALRM',
'SIGXCPU',
'SIGXFSZ',
'SIGWINCH',
];
// ref: https://man7.org/linux/man-pages/man7/signal.7.html

function get_job(body) {
let {
language,
Expand Down Expand Up @@ -250,7 +209,9 @@ router.ws('/connect', async (ws, req) => {
break;
case 'signal':
if (job !== null) {
if (SIGNALS.includes(msg.signal)) {
if (
Object.values(globals.SIGNALS).includes(msg.signal)
) {
event_bus.emit('signal', msg.signal);
} else {
ws.close(4005, 'Invalid signal');
Expand Down
65 changes: 65 additions & 0 deletions api/src/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,70 @@ const platform = `${is_docker() ? 'docker' : 'baremetal'}-${fs
.split('\n')
.find(x => x.startsWith('ID'))
.replace('ID=', '')}`;
const SIGNALS = {
1: 'SIGHUP',
2: 'SIGINT',
3: 'SIGQUIT',
4: 'SIGILL',
5: 'SIGTRAP',
6: 'SIGABRT',
7: 'SIGBUS',
8: 'SIGFPE',
9: 'SIGKILL',
10: 'SIGUSR1',
11: 'SIGSEGV',
12: 'SIGUSR2',
13: 'SIGPIPE',
14: 'SIGALRM',
15: 'SIGTERM',
16: 'SIGSTKFLT',
17: 'SIGCHLD',
18: 'SIGCONT',
19: 'SIGSTOP',
20: 'SIGTSTP',
21: 'SIGTTIN',
22: 'SIGTTOU',
23: 'SIGURG',
24: 'SIGXCPU',
25: 'SIGXFSZ',
26: 'SIGVTALRM',
27: 'SIGPROF',
28: 'SIGWINCH',
29: 'SIGIO',
30: 'SIGPWR',
31: 'SIGSYS',
34: 'SIGRTMIN',
35: 'SIGRTMIN+1',
36: 'SIGRTMIN+2',
37: 'SIGRTMIN+3',
38: 'SIGRTMIN+4',
39: 'SIGRTMIN+5',
40: 'SIGRTMIN+6',
41: 'SIGRTMIN+7',
42: 'SIGRTMIN+8',
43: 'SIGRTMIN+9',
44: 'SIGRTMIN+10',
45: 'SIGRTMIN+11',
46: 'SIGRTMIN+12',
47: 'SIGRTMIN+13',
48: 'SIGRTMIN+14',
49: 'SIGRTMIN+15',
50: 'SIGRTMAX-14',
51: 'SIGRTMAX-13',
52: 'SIGRTMAX-12',
53: 'SIGRTMAX-11',
54: 'SIGRTMAX-10',
55: 'SIGRTMAX-9',
56: 'SIGRTMAX-8',
57: 'SIGRTMAX-7',
58: 'SIGRTMAX-6',
59: 'SIGRTMAX-5',
60: 'SIGRTMAX-4',
61: 'SIGRTMAX-3',
62: 'SIGRTMAX-2',
63: 'SIGRTMAX-1',
64: 'SIGRTMAX',
};

module.exports = {
data_directories: {
Expand All @@ -16,4 +80,5 @@ module.exports = {
platform,
pkg_installed_file: '.ppman-installed', //Used as indication for if a package was installed
clean_directories: ['/dev/shm', '/run/lock', '/tmp', '/var/tmp'],
SIGNALS,
};
50 changes: 10 additions & 40 deletions api/src/job.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const cp = require('child_process');
const path = require('path');
const config = require('./config');
const fs = require('fs/promises');
const globals = require('./globals');

const job_states = {
READY: Symbol('Ready to be primed'),
Expand Down Expand Up @@ -245,18 +246,15 @@ class Job {
});

const data = await new Promise((res, rej) => {
proc.on('close', () => {
proc.on('exit', (_, signal) => {
res({
stdout,
stderr,
signal,
});
});

proc.on('error', err => {
rej({
error: err,
stdout,
stderr,
});
});
});
Expand All @@ -277,31 +275,13 @@ class Job {
}
switch (key) {
case 'cg-mem':
try {
memory = parse_int(value);
} catch (e) {
throw new Error(
`Failed to parse memory usage, received value: ${value}`
);
}
memory = parse_int(value);
break;
case 'exitcode':
try {
code = parse_int(value);
} catch (e) {
throw new Error(
`Failed to parse exit code, received value: ${value}`
);
}
code = parse_int(value);
break;
case 'exitsig':
try {
signal = parse_int(value);
} catch (e) {
throw new Error(
`Failed to parse exit signal, received value: ${value}`
);
}
signal = globals.SIGNALS[parse_int(value)] ?? null;
break;
case 'message':
message = message || value;
Expand All @@ -310,22 +290,10 @@ class Job {
status = value;
break;
case 'time':
try {
cpu_time_stat = parse_float(value);
} catch (e) {
throw new Error(
`Failed to parse cpu time, received value: ${value}`
);
}
cpu_time_stat = parse_float(value) * 1000;
break;
case 'time-wall':
try {
wall_time_stat = parse_float(value);
} catch (e) {
throw new Error(
`Failed to parse wall time, received value: ${value}`
);
}
wall_time_stat = parse_float(value) * 1000;
break;
default:
break;
Expand All @@ -339,6 +307,8 @@ class Job {

return {
...data,
stdout,
stderr,
code,
signal,
output,
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ services:
- 2000:2000
volumes:
- ./data/piston/packages:/piston/packages
environment:
- PISTON_REPO_URL=http://repo:8000/index
tmpfs:
- /piston/jobs:exec,uid=1000,gid=1000,mode=711

Expand Down
17 changes: 15 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,21 @@ key:
default: 3000
```

The maximum time that is allowed to be taken by a stage in milliseconds.
Use -1 for unlimited time.
The maximum time that is allowed to be taken by a stage in milliseconds. This is the wall-time of the stage. The time that the CPU does not spend working on the stage (e.g, due to context switches or IO) is counted.

## Compile/Run CPU-Time

```yaml
key:
- PISTON_COMPILE_CPU_TIME
default: 10000
key:
- PISTON_RUN_CPU_TIME
default: 3000
```

The maximum CPU-time that is allowed to be consumed by a stage in milliseconds. The time that the CPU does not spend working on the stage (e.g, IO and context switches) is not counted. This option is typically used in algorithm contests.

## Compile/Run memory limits

Expand Down
24 changes: 19 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ POST https://emkc.org/api/v2/piston/execute

- Docker
- Docker Compose
- Node JS (>= 13, preferably >= 15)
- Node JS (>= 15)
- cgroup v2 enabled, and cgroup v1 disabled

### After system dependencies are installed, clone this repository:

Expand Down Expand Up @@ -245,8 +246,10 @@ This endpoint requests execution of some arbitrary code.
- `files[].encoding` (_optional_) The encoding scheme used for the file content. One of `base64`, `hex` or `utf8`. Defaults to `utf8`.
- `stdin` (_optional_) The text to pass as stdin to the program. Must be a string or left out. Defaults to blank string.
- `args` (_optional_) The arguments to pass to the program. Must be an array or left out. Defaults to `[]`.
- `compile_timeout` (_optional_) The maximum time allowed for the compile stage to finish before bailing out in milliseconds. Must be a number or left out. Defaults to `10000` (10 seconds).
- `run_timeout` (_optional_) The maximum time allowed for the run stage to finish before bailing out in milliseconds. Must be a number or left out. Defaults to `3000` (3 seconds).
- `compile_timeout` (_optional_) The maximum wall-time allowed for the compile stage to finish before bailing out in milliseconds. Must be a number or left out. Defaults to `10000` (10 seconds).
- `run_timeout` (_optional_) The maximum wall-time allowed for the run stage to finish before bailing out in milliseconds. Must be a number or left out. Defaults to `3000` (3 seconds).
- `compile_cpu_time` (_optional_) The maximum CPU-time allowed for the compile stage to finish before bailing out in milliseconds. Must be a number or left out. Defaults to `10000` (10 seconds).
- `run_cpu_time` (_optional_) The maximum CPU-time allowed for the run stage to finish before bailing out in milliseconds. Must be a number or left out. Defaults to `3000` (3 seconds).
- `compile_memory_limit` (_optional_) The maximum amount of memory the compile stage is allowed to use in bytes. Must be a number or left out. Defaults to `-1` (no limit)
- `run_memory_limit` (_optional_) The maximum amount of memory the run stage is allowed to use in bytes. Must be a number or left out. Defaults to `-1` (no limit)

Expand All @@ -264,6 +267,8 @@ This endpoint requests execution of some arbitrary code.
"args": ["1", "2", "3"],
"compile_timeout": 10000,
"run_timeout": 3000,
"compile_cpu_time": 10000,
"run_cpu_time": 3000,
"compile_memory_limit": -1,
"run_memory_limit": -1
}
Expand All @@ -273,7 +278,12 @@ A typical response upon successful execution will contain 1 or 2 keys `run` and
`compile` will only be present if the language requested requires a compile stage.

Each of these keys has an identical structure, containing both a `stdout` and `stderr` key, which is a string containing the text outputted during the stage into each buffer.
It also contains the `code` and `signal` which was returned from each process.
It also contains the `code` and `signal` which was returned from each process. It also includes a nullable human-readable `message` which is a description of why a stage has failed and a two-letter `status` that is either:

- `RE` for runtime error
- `SG` for dying on a signal
- `TO` for timeout (either via `timeout` or `cpu_time`)
- `XX` for internal error

```json
HTTP/1.1 200 OK
Expand All @@ -287,7 +297,11 @@ Content-Type: application/json
"stderr": "",
"output": "[\n '/piston/packages/node/15.10.0/bin/node',\n '/piston/jobs/9501b09d-0105-496b-b61a-e5148cf66384/my_cool_code.js',\n '1',\n '2',\n '3'\n]\n",
"code": 0,
"signal": null
"signal": null,
"message": null,
"status": null,
"cpu_time": 8,
"wall_time": 154
}
}
```
Expand Down

0 comments on commit 09ff4ca

Please sign in to comment.