LCOV - code coverage report
Current view: top level - ports/unix - moduselect.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-740-gbf49a087b.info Lines: 105 129 81.4 %
Date: 2022-12-09 11:55:04 Functions: 9 9 100.0 %
Branches: 42 78 53.8 %

           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) 2014 Damien P. George
       7                 :            :  * Copyright (c) 2015-2017 Paul Sokolovsky
       8                 :            :  *
       9                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      10                 :            :  * of this software and associated documentation files (the "Software"), to deal
      11                 :            :  * in the Software without restriction, including without limitation the rights
      12                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      13                 :            :  * copies of the Software, and to permit persons to whom the Software is
      14                 :            :  * furnished to do so, subject to the following conditions:
      15                 :            :  *
      16                 :            :  * The above copyright notice and this permission notice shall be included in
      17                 :            :  * all copies or substantial portions of the Software.
      18                 :            :  *
      19                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      24                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      25                 :            :  * THE SOFTWARE.
      26                 :            :  */
      27                 :            : 
      28                 :            : #include "py/mpconfig.h"
      29                 :            : 
      30                 :            : #if MICROPY_PY_USELECT_POSIX
      31                 :            : 
      32                 :            : #if MICROPY_PY_USELECT
      33                 :            : #error "Can't have both MICROPY_PY_USELECT and MICROPY_PY_USELECT_POSIX."
      34                 :            : #endif
      35                 :            : 
      36                 :            : #include <stdio.h>
      37                 :            : #include <errno.h>
      38                 :            : #include <poll.h>
      39                 :            : 
      40                 :            : #include "py/runtime.h"
      41                 :            : #include "py/stream.h"
      42                 :            : #include "py/obj.h"
      43                 :            : #include "py/objlist.h"
      44                 :            : #include "py/objtuple.h"
      45                 :            : #include "py/mphal.h"
      46                 :            : #include "py/mpthread.h"
      47                 :            : 
      48                 :            : #define DEBUG 0
      49                 :            : 
      50                 :            : #if MICROPY_PY_SOCKET
      51                 :            : extern const mp_obj_type_t mp_type_socket;
      52                 :            : #endif
      53                 :            : 
      54                 :            : // Flags for poll()
      55                 :            : #define FLAG_ONESHOT (1)
      56                 :            : 
      57                 :            : /// \class Poll - poll class
      58                 :            : 
      59                 :            : typedef struct _mp_obj_poll_t {
      60                 :            :     mp_obj_base_t base;
      61                 :            :     unsigned short alloc;
      62                 :            :     unsigned short len;
      63                 :            :     struct pollfd *entries;
      64                 :            :     mp_obj_t *obj_map;
      65                 :            :     short iter_cnt;
      66                 :            :     short iter_idx;
      67                 :            :     int flags;
      68                 :            :     // callee-owned tuple
      69                 :            :     mp_obj_t ret_tuple;
      70                 :            : } mp_obj_poll_t;
      71                 :            : 
      72                 :         18 : STATIC int get_fd(mp_obj_t fdlike) {
      73         [ +  - ]:         18 :     if (mp_obj_is_obj(fdlike)) {
      74                 :         18 :         const mp_stream_p_t *stream_p = mp_get_stream_raise(fdlike, MP_STREAM_OP_IOCTL);
      75                 :         18 :         int err;
      76                 :         18 :         mp_uint_t res = stream_p->ioctl(fdlike, MP_STREAM_GET_FILENO, 0, &err);
      77         [ +  - ]:         16 :         if (res != MP_STREAM_ERROR) {
      78                 :         16 :             return res;
      79                 :            :         }
      80                 :            :     }
      81                 :          0 :     return mp_obj_get_int(fdlike);
      82                 :            : }
      83                 :            : 
      84                 :            : /// \method register(obj[, eventmask])
      85                 :         10 : STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
      86                 :         10 :     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
      87   [ +  -  +  -  :         10 :     bool is_fd = mp_obj_is_int(args[1]);
                   -  + ]
      88                 :         10 :     int fd = get_fd(args[1]);
      89                 :            : 
      90                 :          8 :     mp_uint_t flags;
      91         [ +  + ]:          8 :     if (n_args == 3) {
      92                 :          2 :         flags = mp_obj_get_int(args[2]);
      93                 :            :     } else {
      94                 :            :         flags = POLLIN | POLLOUT;
      95                 :            :     }
      96                 :            : 
      97                 :          8 :     struct pollfd *free_slot = NULL;
      98                 :            : 
      99                 :          8 :     struct pollfd *entry = self->entries;
     100         [ +  + ]:         10 :     for (int i = 0; i < self->len; i++, entry++) {
     101                 :          4 :         int entry_fd = entry->fd;
     102         [ +  + ]:          4 :         if (entry_fd == fd) {
     103                 :          2 :             entry->events = flags;
     104                 :          2 :             return mp_const_false;
     105                 :            :         }
     106         [ +  - ]:          2 :         if (entry_fd == -1) {
     107                 :          2 :             free_slot = entry;
     108                 :            :         }
     109                 :            :     }
     110                 :            : 
     111         [ +  + ]:          6 :     if (free_slot == NULL) {
     112         [ -  + ]:          4 :         if (self->len >= self->alloc) {
     113                 :          0 :             self->entries = m_renew(struct pollfd, self->entries, self->alloc, self->alloc + 4);
     114         [ #  # ]:          0 :             if (self->obj_map) {
     115                 :          0 :                 self->obj_map = m_renew(mp_obj_t, self->obj_map, self->alloc, self->alloc + 4);
     116                 :            :             }
     117                 :          0 :             self->alloc += 4;
     118                 :            :         }
     119                 :          4 :         free_slot = &self->entries[self->len++];
     120                 :            :     }
     121                 :            : 
     122         [ +  - ]:          6 :     if (!is_fd) {
     123         [ +  + ]:          6 :         if (self->obj_map == NULL) {
     124                 :          4 :             self->obj_map = m_new0(mp_obj_t, self->alloc);
     125                 :            :         }
     126                 :          6 :         self->obj_map[free_slot - self->entries] = args[1];
     127                 :            :     }
     128                 :            : 
     129                 :          6 :     free_slot->fd = fd;
     130                 :          6 :     free_slot->events = flags;
     131                 :          6 :     free_slot->revents = 0;
     132                 :          6 :     return mp_const_true;
     133                 :            : }
     134                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
     135                 :            : 
     136                 :            : /// \method unregister(obj)
     137                 :          2 : STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
     138                 :          2 :     mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
     139                 :          2 :     struct pollfd *entries = self->entries;
     140                 :          2 :     int fd = get_fd(obj_in);
     141         [ +  - ]:          2 :     for (int i = self->len - 1; i >= 0; i--) {
     142         [ +  - ]:          2 :         if (entries->fd == fd) {
     143                 :          2 :             entries->fd = -1;
     144         [ +  - ]:          2 :             if (self->obj_map) {
     145                 :          2 :                 self->obj_map[entries - self->entries] = MP_OBJ_NULL;
     146                 :            :             }
     147                 :            :             break;
     148                 :            :         }
     149                 :          0 :         entries++;
     150                 :            :     }
     151                 :            : 
     152                 :            :     // TODO raise KeyError if obj didn't exist in map
     153                 :          2 :     return mp_const_none;
     154                 :            : }
     155                 :            : MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
     156                 :            : 
     157                 :            : /// \method modify(obj, eventmask)
     158                 :          6 : STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
     159                 :          6 :     mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
     160                 :          6 :     struct pollfd *entries = self->entries;
     161                 :          6 :     int fd = get_fd(obj_in);
     162         [ +  + ]:          8 :     for (int i = self->len - 1; i >= 0; i--) {
     163         [ +  + ]:          6 :         if (entries->fd == fd) {
     164                 :          4 :             entries->events = mp_obj_get_int(eventmask_in);
     165                 :          4 :             return mp_const_none;
     166                 :            :         }
     167                 :          2 :         entries++;
     168                 :            :     }
     169                 :            : 
     170                 :            :     // obj doesn't exist in poller
     171                 :          2 :     mp_raise_OSError(MP_ENOENT);
     172                 :            : }
     173                 :            : MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify);
     174                 :            : 
     175                 :     182127 : STATIC int poll_poll_internal(size_t n_args, const mp_obj_t *args) {
     176                 :     182127 :     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
     177                 :            : 
     178                 :            :     // work out timeout (it's given already in ms)
     179                 :     182127 :     int timeout = -1;
     180                 :     182127 :     int flags = 0;
     181         [ +  - ]:     182127 :     if (n_args >= 2) {
     182         [ +  - ]:     182127 :         if (args[1] != mp_const_none) {
     183                 :     182127 :             mp_int_t timeout_i = mp_obj_get_int(args[1]);
     184         [ +  - ]:     182127 :             if (timeout_i >= 0) {
     185                 :     182127 :                 timeout = timeout_i;
     186                 :            :             }
     187                 :            :         }
     188         [ -  + ]:     182127 :         if (n_args >= 3) {
     189                 :          0 :             flags = mp_obj_get_int(args[2]);
     190                 :            :         }
     191                 :            :     }
     192                 :            : 
     193                 :     182127 :     self->flags = flags;
     194                 :            : 
     195                 :     182127 :     int n_ready;
     196   [ -  +  -  - ]:     182127 :     MP_HAL_RETRY_SYSCALL(n_ready, poll(self->entries, self->len, timeout), mp_raise_OSError(err));
     197                 :     182127 :     return n_ready;
     198                 :            : }
     199                 :            : 
     200                 :            : /// \method poll([timeout])
     201                 :            : /// Timeout is in milliseconds.
     202                 :          6 : STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) {
     203                 :          6 :     int n_ready = poll_poll_internal(n_args, args);
     204                 :            : 
     205         [ +  + ]:          6 :     if (n_ready == 0) {
     206                 :            :         return mp_const_empty_tuple;
     207                 :            :     }
     208                 :            : 
     209                 :          4 :     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
     210                 :            : 
     211                 :          4 :     mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL));
     212                 :          4 :     int ret_i = 0;
     213                 :          4 :     struct pollfd *entries = self->entries;
     214         [ +  + ]:          8 :     for (int i = 0; i < self->len; i++, entries++) {
     215         [ +  - ]:          4 :         if (entries->revents != 0) {
     216                 :          4 :             mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
     217                 :            :             // If there's an object stored, return it, otherwise raw fd
     218   [ +  -  +  - ]:          4 :             if (self->obj_map && self->obj_map[i] != MP_OBJ_NULL) {
     219                 :          4 :                 t->items[0] = self->obj_map[i];
     220                 :            :             } else {
     221                 :          0 :                 t->items[0] = MP_OBJ_NEW_SMALL_INT(entries->fd);
     222                 :            :             }
     223                 :          4 :             t->items[1] = MP_OBJ_NEW_SMALL_INT(entries->revents);
     224                 :          4 :             ret_list->items[ret_i++] = MP_OBJ_FROM_PTR(t);
     225         [ -  + ]:          4 :             if (self->flags & FLAG_ONESHOT) {
     226                 :          0 :                 entries->events = 0;
     227                 :            :             }
     228                 :            :         }
     229                 :            :     }
     230                 :            : 
     231                 :            :     return MP_OBJ_FROM_PTR(ret_list);
     232                 :            : }
     233                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll);
     234                 :            : 
     235                 :     182121 : STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) {
     236                 :     182121 :     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
     237                 :            : 
     238         [ +  + ]:     182121 :     if (self->ret_tuple == MP_OBJ_NULL) {
     239                 :         52 :         self->ret_tuple = mp_obj_new_tuple(2, NULL);
     240                 :            :     }
     241                 :            : 
     242                 :     182121 :     int n_ready = poll_poll_internal(n_args, args);
     243                 :     182121 :     self->iter_cnt = n_ready;
     244                 :     182121 :     self->iter_idx = 0;
     245                 :            : 
     246                 :     182121 :     return args[0];
     247                 :            : }
     248                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_ipoll_obj, 1, 3, poll_ipoll);
     249                 :            : 
     250                 :     182121 : STATIC mp_obj_t poll_iternext(mp_obj_t self_in) {
     251                 :     182121 :     mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
     252                 :            : 
     253         [ -  + ]:     182121 :     if (self->iter_cnt == 0) {
     254                 :            :         return MP_OBJ_STOP_ITERATION;
     255                 :            :     }
     256                 :            : 
     257                 :          0 :     self->iter_cnt--;
     258                 :            : 
     259                 :          0 :     struct pollfd *entries = self->entries + self->iter_idx;
     260         [ #  # ]:          0 :     for (int i = self->iter_idx; i < self->len; i++, entries++) {
     261                 :          0 :         self->iter_idx++;
     262         [ #  # ]:          0 :         if (entries->revents != 0) {
     263                 :          0 :             mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple);
     264                 :            :             // If there's an object stored, return it, otherwise raw fd
     265   [ #  #  #  # ]:          0 :             if (self->obj_map && self->obj_map[i] != MP_OBJ_NULL) {
     266                 :          0 :                 t->items[0] = self->obj_map[i];
     267                 :            :             } else {
     268                 :          0 :                 t->items[0] = MP_OBJ_NEW_SMALL_INT(entries->fd);
     269                 :            :             }
     270                 :          0 :             t->items[1] = MP_OBJ_NEW_SMALL_INT(entries->revents);
     271         [ #  # ]:          0 :             if (self->flags & FLAG_ONESHOT) {
     272                 :          0 :                 entries->events = 0;
     273                 :            :             }
     274                 :          0 :             return MP_OBJ_FROM_PTR(t);
     275                 :            :         }
     276                 :            :     }
     277                 :            : 
     278                 :          0 :     assert(!"inconsistent number of poll active entries");
     279                 :            :     self->iter_cnt = 0;
     280                 :            :     return MP_OBJ_STOP_ITERATION;
     281                 :            : }
     282                 :            : 
     283                 :            : #if DEBUG
     284                 :            : STATIC mp_obj_t poll_dump(mp_obj_t self_in) {
     285                 :            :     mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
     286                 :            : 
     287                 :            :     struct pollfd *entries = self->entries;
     288                 :            :     for (int i = self->len - 1; i >= 0; i--) {
     289                 :            :         printf("fd: %d ev: %x rev: %x", entries->fd, entries->events, entries->revents);
     290                 :            :         if (self->obj_map) {
     291                 :            :             printf(" obj: %p", self->obj_map[entries - self->entries]);
     292                 :            :         }
     293                 :            :         printf("\n");
     294                 :            :         entries++;
     295                 :            :     }
     296                 :            : 
     297                 :            :     return mp_const_none;
     298                 :            : }
     299                 :            : MP_DEFINE_CONST_FUN_OBJ_1(poll_dump_obj, poll_dump);
     300                 :            : #endif
     301                 :            : 
     302                 :            : STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = {
     303                 :            :     { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) },
     304                 :            :     { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) },
     305                 :            :     { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) },
     306                 :            :     { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) },
     307                 :            :     { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) },
     308                 :            :     #if DEBUG
     309                 :            :     { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&poll_dump_obj) },
     310                 :            :     #endif
     311                 :            : };
     312                 :            : STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table);
     313                 :            : 
     314                 :            : STATIC MP_DEFINE_CONST_OBJ_TYPE(
     315                 :            :     mp_type_poll,
     316                 :            :     MP_QSTR_poll,
     317                 :            :     MP_TYPE_FLAG_ITER_IS_ITERNEXT,
     318                 :            :     iter, poll_iternext,
     319                 :            :     locals_dict, &poll_locals_dict
     320                 :            :     );
     321                 :            : 
     322                 :         60 : STATIC mp_obj_t select_poll(size_t n_args, const mp_obj_t *args) {
     323                 :         60 :     int alloc = 4;
     324         [ -  + ]:         60 :     if (n_args > 0) {
     325                 :          0 :         alloc = mp_obj_get_int(args[0]);
     326                 :            :     }
     327                 :         60 :     mp_obj_poll_t *poll = mp_obj_malloc(mp_obj_poll_t, &mp_type_poll);
     328                 :         60 :     poll->entries = m_new(struct pollfd, alloc);
     329                 :         60 :     poll->alloc = alloc;
     330                 :         60 :     poll->len = 0;
     331                 :         60 :     poll->obj_map = NULL;
     332                 :         60 :     poll->iter_cnt = 0;
     333                 :         60 :     poll->ret_tuple = MP_OBJ_NULL;
     334                 :         60 :     return MP_OBJ_FROM_PTR(poll);
     335                 :            : }
     336                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_poll_obj, 0, 1, select_poll);
     337                 :            : 
     338                 :            : STATIC const mp_rom_map_elem_t mp_module_select_globals_table[] = {
     339                 :            :     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uselect) },
     340                 :            :     { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mp_select_poll_obj) },
     341                 :            :     { MP_ROM_QSTR(MP_QSTR_POLLIN), MP_ROM_INT(POLLIN) },
     342                 :            :     { MP_ROM_QSTR(MP_QSTR_POLLOUT), MP_ROM_INT(POLLOUT) },
     343                 :            :     { MP_ROM_QSTR(MP_QSTR_POLLERR), MP_ROM_INT(POLLERR) },
     344                 :            :     { MP_ROM_QSTR(MP_QSTR_POLLHUP), MP_ROM_INT(POLLHUP) },
     345                 :            : };
     346                 :            : 
     347                 :            : STATIC MP_DEFINE_CONST_DICT(mp_module_select_globals, mp_module_select_globals_table);
     348                 :            : 
     349                 :            : const mp_obj_module_t mp_module_uselect = {
     350                 :            :     .base = { &mp_type_module },
     351                 :            :     .globals = (mp_obj_dict_t *)&mp_module_select_globals,
     352                 :            : };
     353                 :            : 
     354                 :            : MP_REGISTER_MODULE(MP_QSTR_uselect, mp_module_uselect);
     355                 :            : 
     356                 :            : #endif // MICROPY_PY_USELECT_POSIX

Generated by: LCOV version 1.15-5-g462f71d