From ea21d3cd2d5fb7a1f9f7dca73bd2638ab7ff99eb Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Wed, 10 Jan 2018 01:28:42 +0100 Subject: [PATCH] libposix: add support for O_NONBLOCK We keep a list of non blocking fds and use awake to make them not block on read, write, pread and pwrite. --- qa/lib/newlib/104-files-nonblocking.c | 110 ++++++++++++++++++++++++ qa/lib/newlib/build.json | 2 + sys/include/posix.h | 5 +- sys/src/lib/posix/fcntl.c | 7 +- sys/src/lib/posix/files.c | 116 ++++++++++++++++++++++++-- sys/src/lib/posix/internal.h | 1 + 6 files changed, 232 insertions(+), 9 deletions(-) create mode 100644 qa/lib/newlib/104-files-nonblocking.c diff --git a/qa/lib/newlib/104-files-nonblocking.c b/qa/lib/newlib/104-files-nonblocking.c new file mode 100644 index 0000000..b391f70 --- /dev/null +++ b/qa/lib/newlib/104-files-nonblocking.c @@ -0,0 +1,110 @@ +// C program to illustrate +// non I/O blocking calls +#include +#include +#include // library for fcntl function +#include +#include +#include + +#define MSGSIZE 6 +char* msg1 ="hello"; +char* msg2 ="bye !!"; + +void parent_read(int p[]) +{ + int nread; + char buf[MSGSIZE]; + + // write link + close(p[1]); + + while (1) { + + // read call if return -1 then pipe is + // empty because of fcntl + nread = read(p[0], buf, MSGSIZE); + switch (nread) { + case -1: + + // case -1 means pipe is empty and errono + // set EAGAIN + if (errno == EAGAIN) { + printf("(pipe empty)\n"); + sleep(1); + break; + } + + else { + perror("read"); + exit(4); + } + + // case 0 means all bytes are read and EOF(end of conv.) + case 0: + printf("End of conversation\n"); + + // read link + close(p[0]); + + exit(0); + default: + + // text read + // by default return no. of bytes + // which read call read at that time + printf("MSG = %s\n", buf); + } + } +} +void child_write(int p[]) +{ + int i; + + // read link + close(p[0]); + + // write 3 times "hello" in 3 second interval + for (i = 0; i < 3; i++) { + write(p[1], msg1, MSGSIZE); + sleep(3); + } + + // write "bye" one times + write(p[1], msg2, MSGSIZE); + + // here after write all bytes then write end + // doesn't close so read end block but + // because of fcntl block doesn't happen.. + exit(0); +} +int main() +{ + int p[2]; + + // error checking for pipe + if (pipe(p) < 0) + exit(1); + + // error checking for fcntl + if (fcntl(p[0], F_SETFL, O_NONBLOCK) < 0) + exit(2); + + // continued + switch (fork()) { + + // error + case -1: + exit(3); + + // 0 for child process + case 0: + child_write(p); + break; + + default: + parent_read(p); + break; + } + return 0; +} diff --git a/qa/lib/newlib/build.json b/qa/lib/newlib/build.json index 4ad9c0b..9afdbb9 100644 --- a/qa/lib/newlib/build.json +++ b/qa/lib/newlib/build.json @@ -45,6 +45,7 @@ "101-files.c", "102-files.c", "103-files.c", + "104-files-nonblocking.c", "120-fcntl.c", "121-fcntl.c", "200-signals.c", @@ -112,6 +113,7 @@ "101-files.c", "102-files.c", "103-files.c", + "104-files-nonblocking.c", "120-fcntl.c", "121-fcntl.c", "200-signals.c", diff --git a/sys/include/posix.h b/sys/include/posix.h index 68281de..e0885ba 100644 --- a/sys/include/posix.h +++ b/sys/include/posix.h @@ -1,7 +1,7 @@ /* * This file is part of Jehanne. * - * Copyright (C) 2017 Giacomo Tesio + * Copyright (C) 2017-2018 Giacomo Tesio * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -375,6 +375,9 @@ extern int libposix_translate_error(PosixErrorTranslator translation, uintptr_t /* define the value of AT_FDCWD according to the library headers */ extern int libposix_define_at_fdcwd(int AT_FDCWD); +/* define the value of O_NONBLOCK according to the library headers */ +extern int libposix_define_ononblock(int O_NONBLOCK); + /* define the value of a specific PosixError according to the library headers */ extern int libposix_define_errno(PosixError e, int errno); diff --git a/sys/src/lib/posix/fcntl.c b/sys/src/lib/posix/fcntl.c index 5ed4229..7477d5b 100644 --- a/sys/src/lib/posix/fcntl.c +++ b/sys/src/lib/posix/fcntl.c @@ -1,7 +1,7 @@ /* * This file is part of Jehanne. * - * Copyright (C) 2017 Giacomo Tesio + * Copyright (C) 2017-2018 Giacomo Tesio * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -21,6 +21,8 @@ #include #include "internal.h" +extern int __libposix_O_NONBLOCK; + static int fcntl_dup(int *errnop, int fd, int minfd) { @@ -150,8 +152,9 @@ POSIX_fcntl(int *errnop, int fd, PosixFDCmds cmd, uintptr_t arg) return -1; return flags & (~OCEXEC); case PosixFDCSetFL: + flags = (int)arg; + __libposix_set_non_blocking(fd, flags & __libposix_O_NONBLOCK); return 0; - break; } *errnop = __libposix_get_errno(PosixEINVAL); diff --git a/sys/src/lib/posix/files.c b/sys/src/lib/posix/files.c index d233af7..fa76288 100644 --- a/sys/src/lib/posix/files.c +++ b/sys/src/lib/posix/files.c @@ -1,7 +1,7 @@ /* * This file is part of Jehanne. * - * Copyright (C) 2017 Giacomo Tesio + * Copyright (C) 2017-2018 Giacomo Tesio * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -33,6 +33,11 @@ static int *__libposix_coe_fds; static int __libposix_coe_fds_size; static int __libposix_coe_fds_used; +int __libposix_O_NONBLOCK; +static int *__libposix_nb_fds; +static int __libposix_nb_fds_size; +static int __libposix_nb_fds_used; + typedef enum SeekTypes { SeekSet = 0, @@ -117,6 +122,53 @@ __libposix_should_close_on_exec(int fd) return 0; } +void +__libposix_set_non_blocking(int fd, int enable) +{ + int i; + if(__libposix_nb_fds_size == __libposix_nb_fds_used){ + __libposix_nb_fds_size += 8; + __libposix_nb_fds = realloc(__libposix_nb_fds, __libposix_nb_fds_size * sizeof(int)); + i = __libposix_nb_fds_size; + while(i > __libposix_nb_fds_used) + __libposix_nb_fds[--i] = -1; + } + /* remove fd if already present */ + i = 0; + while(i < __libposix_nb_fds_size){ + if(__libposix_nb_fds[i] == fd){ + __libposix_nb_fds[i] = -1; + --__libposix_nb_fds_used; + break; + } + ++i; + } + if(enable){ + /* add fd to ensure it will not block */ + i = 0; + while(i < __libposix_nb_fds_size){ + if(__libposix_nb_fds[i] == -1){ + __libposix_nb_fds[i] = fd; + break; + } + ++i; + } + ++__libposix_nb_fds_used; + } +} + +int +__libposix_should_not_block(int fd) +{ + int i = 0; + while(i < __libposix_nb_fds_size){ + if(__libposix_nb_fds[i] == fd) + return 1; + ++i; + } + return 0; +} + int libposix_translate_open(PosixOpenTranslator translation) { @@ -295,8 +347,11 @@ POSIX_open(int *errnop, const char *name, int flags, int mode) } else { f = ocreate(name, (unsigned int)omode, (unsigned int)cperm); } - if(f >= 0) + if(f >= 0){ + if(flags & __libposix_O_NONBLOCK) + __libposix_set_non_blocking(f, 1); return f; + } *errnop = __libposix_translate_errstr((uintptr_t)POSIX_open); return -1; @@ -308,40 +363,60 @@ FailWithError: long POSIX_read(int *errnop, int fd, char *buf, size_t len) { - long r; + long r, wkp = 0; if(fd < 0){ *errnop = __libposix_get_errno(PosixEBADF); return -1; } OnIgnoredSignalInterrupt: + if(__libposix_should_not_block(fd)) + wkp = awake(2); r = sys_pread(fd, buf, len, -1); if(r < 0){ + if(wkp){ + if(!awakened(wkp)) + forgivewkp(wkp); + *errnop = __libposix_get_errno(PosixEAGAIN); + return -1; + } if(__libposix_restart_syscall()) goto OnIgnoredSignalInterrupt; *errnop = __libposix_translate_errstr((uintptr_t)POSIX_read); return -1; } + if(wkp) + forgivewkp(wkp); return r; } long POSIX_write(int *errnop, int fd, const void *buf, size_t len) { - long w; + long w, wkp = 0; if(fd < 0){ *errnop = __libposix_get_errno(PosixEBADF); return -1; } OnIgnoredSignalInterrupt: + if(__libposix_should_not_block(fd)) + wkp = awake(2); w = sys_pwrite(fd, buf, len, -1); if(w < 0){ + if(wkp){ + if(!awakened(wkp)) + forgivewkp(wkp); + *errnop = __libposix_get_errno(PosixEAGAIN); + return -1; + } if(__libposix_restart_syscall()) goto OnIgnoredSignalInterrupt; *errnop = __libposix_translate_errstr((uintptr_t)POSIX_write); return -1; } + if(wkp) + forgivewkp(wkp); return w; } @@ -370,40 +445,60 @@ POSIX_lseek(int *errnop, int fd, off_t pos, int whence) long POSIX_pread(int *errnop, int fd, char *buf, size_t len, long offset) { - long r; + long r, wkp = 0; if(fd < 0){ *errnop = __libposix_get_errno(PosixEBADF); return -1; } OnIgnoredSignalInterrupt: + if(__libposix_should_not_block(fd)) + wkp = awake(2); r = sys_pread(fd, buf, len, offset); if(r < 0){ + if(wkp){ + if(!awakened(wkp)) + forgivewkp(wkp); + *errnop = __libposix_get_errno(PosixEAGAIN); + return -1; + } if(__libposix_restart_syscall()) goto OnIgnoredSignalInterrupt; *errnop = __libposix_translate_errstr((uintptr_t)POSIX_read); return -1; } + if(wkp) + forgivewkp(wkp); return r; } long POSIX_pwrite(int *errnop, int fd, const char *buf, size_t len, long offset) { - long w; + long w, wkp = 0; if(fd < 0){ *errnop = __libposix_get_errno(PosixEBADF); return -1; } OnIgnoredSignalInterrupt: + if(__libposix_should_not_block(fd)) + wkp = awake(2); w = sys_pwrite(fd, buf, len, offset); if(w < 0){ + if(wkp){ + if(!awakened(wkp)) + forgivewkp(wkp); + *errnop = __libposix_get_errno(PosixEAGAIN); + return -1; + } if(__libposix_restart_syscall()) goto OnIgnoredSignalInterrupt; *errnop = __libposix_translate_errstr((uintptr_t)POSIX_write); return -1; } + if(wkp) + forgivewkp(wkp); return w; } @@ -881,3 +976,12 @@ libposix_define_at_fdcwd(int AT_FDCWD) __libposix_AT_FDCWD = AT_FDCWD; return 0; } + +int +libposix_define_ononblock(int O_NONBLOCK) +{ + if(__libposix_O_NONBLOCK != 0) + return -1; + __libposix_O_NONBLOCK = O_NONBLOCK; + return 0; +} diff --git a/sys/src/lib/posix/internal.h b/sys/src/lib/posix/internal.h index 8469855..2276466 100644 --- a/sys/src/lib/posix/internal.h +++ b/sys/src/lib/posix/internal.h @@ -142,3 +142,4 @@ extern long __libposix_sighelper_set(PosixHelperCommand command, PosixSignalMask extern long __libposix_sighelper_signal(PosixHelperCommand command, int target, PosixSignalInfo *siginfo); extern long __libposix_sighelper_wait(PosixSignalMask set, PosixSignalInfo *siginfo); extern long __libposix_sighelper_set_pgid(int target, int group_id); +extern void __libposix_set_non_blocking(int fd, int enable);