From 082b12128d935eaf7ac49560c90734def1d0b232 Mon Sep 17 00:00:00 2001
From: Paul Sokolovsky <pfalcon@users.sourceforge.net>
Date: Sat, 5 Dec 2015 14:53:53 +0200
Subject: [PATCH] unix/moduselect: register(): Allow to call with duplicate
 file descriptor.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Per CPython docs, "Registering a file descriptor that’s already registered
is not an error, and has the same effect as registering the descriptor
exactly once."
https://docs.python.org/3/library/select.html#select.poll.register

That's somewhat ambiguous, what's implemented here is that if fd si not
yet registered, it is registered. Otherwise, the effect is equivalent to
modify() method.
---
 unix/moduselect.c | 37 +++++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/unix/moduselect.c b/unix/moduselect.c
index 9abcc19dd..b86084b18 100644
--- a/unix/moduselect.c
+++ b/unix/moduselect.c
@@ -47,6 +47,7 @@ typedef struct _mp_obj_poll_t {
 /// \method register(obj[, eventmask])
 STATIC mp_obj_t poll_register(uint n_args, const mp_obj_t *args) {
     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
+    int fd = mp_obj_get_int(args[1]);
     mp_uint_t flags;
     if (n_args == 3) {
         flags = mp_obj_get_int(args[2]);
@@ -54,28 +55,32 @@ STATIC mp_obj_t poll_register(uint n_args, const mp_obj_t *args) {
         flags = POLLIN | POLLOUT;
     }
 
-    int i = 0;
-    if (self->len < self->alloc) {
-        i = self->len++;
-    } else {
-        struct pollfd *entries = self->entries;
-        for (i = 0; i < self->len; i++, entries++) {
-            if (entries->fd == -1) {
-                break;
-            }
+    struct pollfd *free_slot = NULL;
+
+    struct pollfd *entry = self->entries;
+    for (int i = 0; i < self->len; i++, entry++) {
+        int entry_fd = entry->fd;
+        if (entry_fd == fd) {
+            entry->events = flags;
+            return mp_const_false;
+        }
+        if (entry_fd == -1) {
+            free_slot = entry;
         }
-        if (entries->fd != -1) {
-            i = self->len++;
+    }
+
+    if (free_slot == NULL) {
+        if (self->len >= self->alloc) {
             self->entries = m_renew(struct pollfd, self->entries, self->alloc, self->alloc + 4);
             self->alloc += 4;
         }
+        free_slot = &self->entries[self->len++];
     }
 
-    self->entries[i].fd = mp_obj_get_int(args[1]);
-    self->entries[i].events = flags;
-    self->entries[i].revents = 0;
-
-    return mp_const_none;
+    free_slot->fd = fd;
+    free_slot->events = flags;
+    free_slot->revents = 0;
+    return mp_const_true;
 }
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
 
-- 
GitLab