Skip to content

Commit 9418611

Browse files
dlechdpgeorge
authored andcommitted
unix: Implement PEP 475 to retry syscalls failing with EINTR.
https://www.python.org/dev/peps/pep-0475/ This implements something similar to PEP 475 on the unix port, and for the VfsPosix class. There are a few differences from the CPython implementation: - Since we call mp_handle_pending() between any ENITR's, additional functions could be called if MICROPY_ENABLE_SCHEDULER is enabled, not just signal handlers. - CPython only handles signal on the main thread, so other threads will raise InterruptedError instead of retrying. On MicroPython, mp_handle_pending() will currently raise exceptions on any thread. A new macro MP_HAL_RETRY_SYSCALL is introduced to reduce duplicated code and ensure that all instances behave the same. This will also allow other ports that use POSIX-like system calls (and use, eg, VfsPosix) to provide their own implementation if needed.
1 parent 5e6cee0 commit 9418611

File tree

10 files changed

+122
-133
lines changed

10 files changed

+122
-133
lines changed

extmod/vfs_posix.c

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "py/runtime.h"
2828
#include "py/mperrno.h"
29+
#include "py/mphal.h"
2930
#include "py/mpthread.h"
3031
#include "extmod/vfs.h"
3132
#include "extmod/vfs_posix.h"
@@ -290,12 +291,8 @@ STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) {
290291
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
291292
struct stat sb;
292293
const char *path = vfs_posix_get_path_str(self, path_in);
293-
MP_THREAD_GIL_EXIT();
294-
int ret = stat(path, &sb);
295-
MP_THREAD_GIL_ENTER();
296-
if (ret != 0) {
297-
mp_raise_OSError(errno);
298-
}
294+
int ret;
295+
MP_HAL_RETRY_SYSCALL(ret, stat(path, &sb), mp_raise_OSError(err));
299296
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
300297
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
301298
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino);
@@ -335,12 +332,8 @@ STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) {
335332
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
336333
STRUCT_STATVFS sb;
337334
const char *path = vfs_posix_get_path_str(self, path_in);
338-
MP_THREAD_GIL_EXIT();
339-
int ret = STATVFS(path, &sb);
340-
MP_THREAD_GIL_ENTER();
341-
if (ret != 0) {
342-
mp_raise_OSError(errno);
343-
}
335+
int ret;
336+
MP_HAL_RETRY_SYSCALL(ret, STATVFS(path, &sb), mp_raise_OSError(err));
344337
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
345338
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);
346339
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize);

extmod/vfs_posix_file.c

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include "py/mphal.h"
2728
#include "py/mpthread.h"
2829
#include "py/runtime.h"
2930
#include "py/stream.h"
@@ -102,12 +103,8 @@ mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_
102103
}
103104

104105
const char *fname = mp_obj_str_get_str(fid);
105-
MP_THREAD_GIL_EXIT();
106-
int fd = open(fname, mode_x | mode_rw, 0644);
107-
MP_THREAD_GIL_ENTER();
108-
if (fd == -1) {
109-
mp_raise_OSError(errno);
110-
}
106+
int fd;
107+
MP_HAL_RETRY_SYSCALL(fd, open(fname, mode_x | mode_rw, 0644), mp_raise_OSError(err));
111108
o->fd = fd;
112109
return MP_OBJ_FROM_PTR(o);
113110
}
@@ -139,14 +136,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vf
139136
STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
140137
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
141138
check_fd_is_open(o);
142-
MP_THREAD_GIL_EXIT();
143-
mp_int_t r = read(o->fd, buf, size);
144-
MP_THREAD_GIL_ENTER();
145-
if (r == -1) {
146-
*errcode = errno;
139+
ssize_t r;
140+
MP_HAL_RETRY_SYSCALL(r, read(o->fd, buf, size), {
141+
*errcode = err;
147142
return MP_STREAM_ERROR;
148-
}
149-
return r;
143+
});
144+
return (mp_uint_t)r;
150145
}
151146

152147
STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
@@ -158,46 +153,33 @@ STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t
158153
return size;
159154
}
160155
#endif
161-
MP_THREAD_GIL_EXIT();
162-
mp_int_t r = write(o->fd, buf, size);
163-
MP_THREAD_GIL_ENTER();
164-
while (r == -1 && errno == EINTR) {
165-
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
166-
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
167-
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
168-
nlr_raise(obj);
169-
}
170-
MP_THREAD_GIL_EXIT();
171-
r = write(o->fd, buf, size);
172-
MP_THREAD_GIL_ENTER();
173-
}
174-
if (r == -1) {
175-
*errcode = errno;
156+
ssize_t r;
157+
MP_HAL_RETRY_SYSCALL(r, write(o->fd, buf, size), {
158+
*errcode = err;
176159
return MP_STREAM_ERROR;
177-
}
178-
return r;
160+
});
161+
return (mp_uint_t)r;
179162
}
180163

181164
STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
182165
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
183166
check_fd_is_open(o);
184167
switch (request) {
185-
case MP_STREAM_FLUSH:
186-
MP_THREAD_GIL_EXIT();
187-
int ret = fsync(o->fd);
188-
MP_THREAD_GIL_ENTER();
189-
if (ret == -1) {
190-
if (errno == EINVAL
168+
case MP_STREAM_FLUSH: {
169+
int ret;
170+
MP_HAL_RETRY_SYSCALL(ret, fsync(o->fd), {
171+
if (err == EINVAL
191172
&& (o->fd == STDIN_FILENO || o->fd == STDOUT_FILENO || o->fd == STDERR_FILENO)) {
192173
// fsync(stdin/stdout/stderr) may fail with EINVAL, but don't propagate that
193174
// error out. Because data is not buffered by us, and stdin/out/err.flush()
194175
// should just be a no-op.
195176
return 0;
196177
}
197-
*errcode = errno;
178+
*errcode = err;
198179
return MP_STREAM_ERROR;
199-
}
180+
});
200181
return 0;
182+
}
201183
case MP_STREAM_SEEK: {
202184
struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg;
203185
MP_THREAD_GIL_EXIT();

ports/unix/input.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include <errno.h>
2728
#include <stdio.h>
2829
#include <stdlib.h>
2930
#include <string.h>
@@ -74,6 +75,9 @@ void prompt_read_history(void) {
7475
char c;
7576
int sz = read(fd, &c, 1);
7677
if (sz < 0) {
78+
if (errno == EINTR) {
79+
continue;
80+
}
7781
break;
7882
}
7983
if (sz == 0 || c == '\n') {
@@ -107,10 +111,10 @@ void prompt_write_history(void) {
107111
for (int i = MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)) - 1; i >= 0; i--) {
108112
const char *line = MP_STATE_PORT(readline_hist)[i];
109113
if (line != NULL) {
110-
int res;
111-
res = write(fd, line, strlen(line));
112-
res = write(fd, "\n", 1);
113-
(void)res;
114+
while (write(fd, line, strlen(line)) == -1 && errno == EINTR) {
115+
}
116+
while (write(fd, "\n", 1) == -1 && errno == EINTR) {
117+
}
114118
}
115119
}
116120
close(fd);

ports/unix/main.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,9 @@ long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);
6464

6565
STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
6666
(void)env;
67-
MP_THREAD_GIL_EXIT();
68-
ssize_t dummy = write(STDERR_FILENO, str, len);
69-
MP_THREAD_GIL_ENTER();
67+
ssize_t ret;
68+
MP_HAL_RETRY_SYSCALL(ret, write(STDERR_FILENO, str, len), {});
7069
mp_uos_dupterm_tx_strn(str, len);
71-
(void)dummy;
7270
}
7371

7472
const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};

ports/unix/modos.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,8 @@ STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) {
5353
struct stat sb;
5454
const char *path = mp_obj_str_get_str(path_in);
5555

56-
MP_THREAD_GIL_EXIT();
57-
int res = stat(path, &sb);
58-
MP_THREAD_GIL_ENTER();
59-
RAISE_ERRNO(res, errno);
56+
int res;
57+
MP_HAL_RETRY_SYSCALL(res, stat(path, &sb), mp_raise_OSError(err));
6058

6159
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
6260
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
@@ -95,10 +93,8 @@ STATIC mp_obj_t mod_os_statvfs(mp_obj_t path_in) {
9593
STRUCT_STATVFS sb;
9694
const char *path = mp_obj_str_get_str(path_in);
9795

98-
MP_THREAD_GIL_EXIT();
99-
int res = STATVFS(path, &sb);
100-
MP_THREAD_GIL_ENTER();
101-
RAISE_ERRNO(res, errno);
96+
int res;
97+
MP_HAL_RETRY_SYSCALL(res, STATVFS(path, &sb), mp_raise_OSError(err));
10298

10399
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
104100
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);

ports/unix/modtime.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,16 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) {
117117
}
118118
RAISE_ERRNO(res, errno);
119119
#else
120-
// TODO: Handle EINTR
121-
MP_THREAD_GIL_EXIT();
122-
sleep(mp_obj_get_int(arg));
123-
MP_THREAD_GIL_ENTER();
120+
int seconds = mp_obj_get_int(arg);
121+
for (;;) {
122+
MP_THREAD_GIL_EXIT();
123+
seconds = sleep(seconds);
124+
MP_THREAD_GIL_ENTER();
125+
if (seconds == 0) {
126+
break;
127+
}
128+
mp_handle_pending(true);
129+
}
124130
#endif
125131
return mp_const_none;
126132
}

ports/unix/moduselect.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,8 @@ STATIC int poll_poll_internal(size_t n_args, const mp_obj_t *args) {
188188

189189
self->flags = flags;
190190

191-
MP_THREAD_GIL_EXIT();
192-
int n_ready = poll(self->entries, self->len, timeout);
193-
MP_THREAD_GIL_ENTER();
194-
RAISE_ERRNO(n_ready, errno);
191+
int n_ready;
192+
MP_HAL_RETRY_SYSCALL(n_ready, poll(self->entries, self->len, timeout), mp_raise_OSError(err));
195193
return n_ready;
196194
}
197195

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy