LCOV - code coverage report
Current view: top level - ports/unix - unix_mphal.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-740-gbf49a087b.info Lines: 66 75 88.0 %
Date: 2022-12-09 11:55:04 Functions: 12 13 92.3 %
Branches: 10 20 50.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2015 Damien P. George
       7                 :            :  *
       8                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       9                 :            :  * of this software and associated documentation files (the "Software"), to deal
      10                 :            :  * in the Software without restriction, including without limitation the rights
      11                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12                 :            :  * copies of the Software, and to permit persons to whom the Software is
      13                 :            :  * furnished to do so, subject to the following conditions:
      14                 :            :  *
      15                 :            :  * The above copyright notice and this permission notice shall be included in
      16                 :            :  * all copies or substantial portions of the Software.
      17                 :            :  *
      18                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      24                 :            :  * THE SOFTWARE.
      25                 :            :  */
      26                 :            : 
      27                 :            : #include <unistd.h>
      28                 :            : #include <stdlib.h>
      29                 :            : #include <string.h>
      30                 :            : #include <time.h>
      31                 :            : #include <sys/time.h>
      32                 :            : #include <fcntl.h>
      33                 :            : 
      34                 :            : #include "py/mphal.h"
      35                 :            : #include "py/mpthread.h"
      36                 :            : #include "py/runtime.h"
      37                 :            : #include "extmod/misc.h"
      38                 :            : 
      39                 :            : #if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
      40                 :            : #if __GLIBC_PREREQ(2, 25)
      41                 :            : #include <sys/random.h>
      42                 :            : #define _HAVE_GETRANDOM
      43                 :            : #endif
      44                 :            : #endif
      45                 :            : 
      46                 :            : #ifndef _WIN32
      47                 :            : #include <signal.h>
      48                 :            : 
      49                 :          0 : STATIC void sighandler(int signum) {
      50         [ #  # ]:          0 :     if (signum == SIGINT) {
      51                 :            :         #if MICROPY_ASYNC_KBD_INTR
      52                 :            :         #if MICROPY_PY_THREAD_GIL
      53                 :            :         // Since signals can occur at any time, we may not be holding the GIL when
      54                 :            :         // this callback is called, so it is not safe to raise an exception here
      55                 :            :         #error "MICROPY_ASYNC_KBD_INTR and MICROPY_PY_THREAD_GIL are not compatible"
      56                 :            :         #endif
      57                 :          0 :         mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
      58                 :          0 :         sigset_t mask;
      59                 :          0 :         sigemptyset(&mask);
      60                 :            :         // On entry to handler, its signal is blocked, and unblocked on
      61                 :            :         // normal exit. As we instead perform longjmp, unblock it manually.
      62                 :          0 :         sigprocmask(SIG_SETMASK, &mask, NULL);
      63                 :          0 :         nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
      64                 :            :         #else
      65                 :            :         if (MP_STATE_MAIN_THREAD(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
      66                 :            :             // this is the second time we are called, so die straight away
      67                 :            :             exit(1);
      68                 :            :         }
      69                 :            :         mp_sched_keyboard_interrupt();
      70                 :            :         #endif
      71                 :            :     }
      72                 :          0 : }
      73                 :            : #endif
      74                 :            : 
      75                 :       4196 : void mp_hal_set_interrupt_char(char c) {
      76                 :            :     // configure terminal settings to (not) let ctrl-C through
      77         [ +  + ]:       4196 :     if (c == CHAR_CTRL_C) {
      78                 :            :         #ifndef _WIN32
      79                 :            :         // enable signal handler
      80                 :       2100 :         struct sigaction sa;
      81                 :       2100 :         sa.sa_flags = 0;
      82                 :       2100 :         sa.sa_handler = sighandler;
      83                 :       2100 :         sigemptyset(&sa.sa_mask);
      84                 :       2100 :         sigaction(SIGINT, &sa, NULL);
      85                 :            :         #endif
      86                 :            :     } else {
      87                 :            :         #ifndef _WIN32
      88                 :            :         // disable signal handler
      89                 :       2096 :         struct sigaction sa;
      90                 :       2096 :         sa.sa_flags = 0;
      91                 :       2096 :         sa.sa_handler = SIG_DFL;
      92                 :       2096 :         sigemptyset(&sa.sa_mask);
      93                 :       2096 :         sigaction(SIGINT, &sa, NULL);
      94                 :            :         #endif
      95                 :            :     }
      96                 :       4196 : }
      97                 :            : 
      98                 :            : #if MICROPY_USE_READLINE == 1
      99                 :            : 
     100                 :            : #include <termios.h>
     101                 :            : 
     102                 :            : static struct termios orig_termios;
     103                 :            : 
     104                 :        239 : void mp_hal_stdio_mode_raw(void) {
     105                 :            :     // save and set terminal settings
     106                 :        239 :     tcgetattr(0, &orig_termios);
     107                 :        239 :     static struct termios termios;
     108                 :        239 :     termios = orig_termios;
     109                 :        239 :     termios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
     110                 :        239 :     termios.c_cflag = (termios.c_cflag & ~(CSIZE | PARENB)) | CS8;
     111                 :        239 :     termios.c_lflag = 0;
     112                 :        239 :     termios.c_cc[VMIN] = 1;
     113                 :        239 :     termios.c_cc[VTIME] = 0;
     114                 :        239 :     tcsetattr(0, TCSAFLUSH, &termios);
     115                 :        239 : }
     116                 :            : 
     117                 :        239 : void mp_hal_stdio_mode_orig(void) {
     118                 :            :     // restore terminal settings
     119                 :        239 :     tcsetattr(0, TCSAFLUSH, &orig_termios);
     120                 :        239 : }
     121                 :            : 
     122                 :            : #endif
     123                 :            : 
     124                 :            : #if MICROPY_PY_OS_DUPTERM
     125                 :            : static int call_dupterm_read(size_t idx) {
     126                 :            :     nlr_buf_t nlr;
     127                 :            :     if (nlr_push(&nlr) == 0) {
     128                 :            :         mp_obj_t read_m[3];
     129                 :            :         mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_read, read_m);
     130                 :            :         read_m[2] = MP_OBJ_NEW_SMALL_INT(1);
     131                 :            :         mp_obj_t res = mp_call_method_n_kw(1, 0, read_m);
     132                 :            :         if (res == mp_const_none) {
     133                 :            :             return -2;
     134                 :            :         }
     135                 :            :         mp_buffer_info_t bufinfo;
     136                 :            :         mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ);
     137                 :            :         if (bufinfo.len == 0) {
     138                 :            :             mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n");
     139                 :            :             MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
     140                 :            :             return -1;
     141                 :            :         }
     142                 :            :         nlr_pop();
     143                 :            :         return *(byte *)bufinfo.buf;
     144                 :            :     } else {
     145                 :            :         // Temporarily disable dupterm to avoid infinite recursion
     146                 :            :         mp_obj_t save_term = MP_STATE_VM(dupterm_objs[idx]);
     147                 :            :         MP_STATE_VM(dupterm_objs[idx]) = NULL;
     148                 :            :         mp_printf(&mp_plat_print, "dupterm: ");
     149                 :            :         mp_obj_print_exception(&mp_plat_print, nlr.ret_val);
     150                 :            :         MP_STATE_VM(dupterm_objs[idx]) = save_term;
     151                 :            :     }
     152                 :            : 
     153                 :            :     return -1;
     154                 :            : }
     155                 :            : #endif
     156                 :            : 
     157                 :       4477 : int mp_hal_stdin_rx_chr(void) {
     158                 :            :     #if MICROPY_PY_OS_DUPTERM
     159                 :            :     // TODO only support dupterm one slot at the moment
     160                 :            :     if (MP_STATE_VM(dupterm_objs[0]) != MP_OBJ_NULL) {
     161                 :            :         int c;
     162                 :            :         do {
     163                 :            :             c = call_dupterm_read(0);
     164                 :            :         } while (c == -2);
     165                 :            :         if (c == -1) {
     166                 :            :             goto main_term;
     167                 :            :         }
     168                 :            :         if (c == '\n') {
     169                 :            :             c = '\r';
     170                 :            :         }
     171                 :            :         return c;
     172                 :            :     }
     173                 :            : main_term:;
     174                 :            :     #endif
     175                 :            : 
     176                 :       4477 :     unsigned char c;
     177                 :       4477 :     ssize_t ret;
     178   [ -  +  -  - ]:       4477 :     MP_HAL_RETRY_SYSCALL(ret, read(STDIN_FILENO, &c, 1), {});
     179         [ -  + ]:       4477 :     if (ret == 0) {
     180                 :          0 :         c = 4; // EOF, ctrl-D
     181         [ +  + ]:       4477 :     } else if (c == '\n') {
     182                 :        263 :         c = '\r';
     183                 :            :     }
     184                 :       4477 :     return c;
     185                 :            : }
     186                 :            : 
     187                 :      29454 : void mp_hal_stdout_tx_strn(const char *str, size_t len) {
     188                 :      29454 :     ssize_t ret;
     189   [ -  +  -  - ]:      29454 :     MP_HAL_RETRY_SYSCALL(ret, write(STDOUT_FILENO, str, len), {});
     190                 :      29454 :     mp_uos_dupterm_tx_strn(str, len);
     191                 :      29454 : }
     192                 :            : 
     193                 :            : // cooked is same as uncooked because the terminal does some postprocessing
     194                 :      20476 : void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
     195                 :      20476 :     mp_hal_stdout_tx_strn(str, len);
     196                 :      20476 : }
     197                 :            : 
     198                 :        638 : void mp_hal_stdout_tx_str(const char *str) {
     199                 :        638 :     mp_hal_stdout_tx_strn(str, strlen(str));
     200                 :        638 : }
     201                 :            : 
     202                 :            : #ifndef mp_hal_ticks_ms
     203                 :     386488 : mp_uint_t mp_hal_ticks_ms(void) {
     204                 :            :     #if (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK)
     205                 :     386488 :     struct timespec tv;
     206                 :     386488 :     clock_gettime(CLOCK_MONOTONIC, &tv);
     207                 :     386488 :     return tv.tv_sec * 1000 + tv.tv_nsec / 1000000;
     208                 :            :     #else
     209                 :            :     struct timeval tv;
     210                 :            :     gettimeofday(&tv, NULL);
     211                 :            :     return tv.tv_sec * 1000 + tv.tv_usec / 1000;
     212                 :            :     #endif
     213                 :            : }
     214                 :            : #endif
     215                 :            : 
     216                 :            : #ifndef mp_hal_ticks_us
     217                 :        163 : mp_uint_t mp_hal_ticks_us(void) {
     218                 :            :     #if (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK)
     219                 :        163 :     struct timespec tv;
     220                 :        163 :     clock_gettime(CLOCK_MONOTONIC, &tv);
     221                 :        163 :     return tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
     222                 :            :     #else
     223                 :            :     struct timeval tv;
     224                 :            :     gettimeofday(&tv, NULL);
     225                 :            :     return tv.tv_sec * 1000000 + tv.tv_usec;
     226                 :            :     #endif
     227                 :            : }
     228                 :            : #endif
     229                 :            : 
     230                 :            : #ifndef mp_hal_time_ns
     231                 :       1158 : uint64_t mp_hal_time_ns(void) {
     232                 :       1158 :     struct timeval tv;
     233                 :       1158 :     gettimeofday(&tv, NULL);
     234                 :       1158 :     return (uint64_t)tv.tv_sec * 1000000000ULL + (uint64_t)tv.tv_usec * 1000ULL;
     235                 :            : }
     236                 :            : #endif
     237                 :            : 
     238                 :            : #ifndef mp_hal_delay_ms
     239                 :         84 : void mp_hal_delay_ms(mp_uint_t ms) {
     240                 :            :     #ifdef MICROPY_EVENT_POLL_HOOK
     241                 :         84 :     mp_uint_t start = mp_hal_ticks_ms();
     242         [ +  + ]:      10609 :     while (mp_hal_ticks_ms() - start < ms) {
     243                 :            :         // MICROPY_EVENT_POLL_HOOK does usleep(500).
     244                 :      10532 :         MICROPY_EVENT_POLL_HOOK
     245                 :            :     }
     246                 :            :     #else
     247                 :            :     // TODO: POSIX et al. define usleep() as guaranteedly capable only of 1s sleep:
     248                 :            :     // "The useconds argument shall be less than one million."
     249                 :            :     usleep(ms * 1000);
     250                 :            :     #endif
     251                 :         77 : }
     252                 :            : #endif
     253                 :            : 
     254                 :         16 : void mp_hal_get_random(size_t n, void *buf) {
     255                 :            :     #ifdef _HAVE_GETRANDOM
     256         [ -  + ]:         16 :     RAISE_ERRNO(getrandom(buf, n, 0), errno);
     257                 :            :     #else
     258                 :            :     int fd = open("/dev/urandom", O_RDONLY);
     259                 :            :     RAISE_ERRNO(fd, errno);
     260                 :            :     RAISE_ERRNO(read(fd, buf, n), errno);
     261                 :            :     close(fd);
     262                 :            :     #endif
     263                 :         16 : }

Generated by: LCOV version 1.15-5-g462f71d