Browse Source

[LibOS] Comprehensive cleanup of epoll_create()/epoll_ctl()/epoll_wait()

Accurate cleanup of shim_do_epoll_create1(), shim_do_epoll_ctl(),
shim_do_epoll_wait(), and other epoll helper functions. This cleanup
also adds error handling (missing previously).

The commit makes (most of) the corresponding LTP tests pass now.

Note that epoll semantics are still incorrect and inefficient: current
epoll_wait() emulation returns only one event to the user.
Dmitrii Kuvaiskii 4 years ago
parent
commit
56bc2b49ad
3 changed files with 192 additions and 171 deletions
  1. 12 12
      LibOS/shim/include/shim_handle.h
  2. 1 1
      LibOS/shim/src/bookkeep/shim_handle.c
  3. 179 158
      LibOS/shim/src/sys/shim_epoll.c

+ 12 - 12
LibOS/shim/include/shim_handle.h

@@ -300,27 +300,27 @@ struct shim_str_handle {
     char* ptr;
 };
 
-DEFINE_LIST(shim_epoll_fd);
-DEFINE_LISTP(shim_epoll_fd);
+DEFINE_LIST(shim_epoll_item);
+DEFINE_LISTP(shim_epoll_item);
 struct shim_epoll_handle {
     int maxfds;
-    int nfds;
-    LISTP_TYPE(shim_epoll_fd) fds; /* this list contains all the
-                                    * shim_epoll_fd objects in correspondence
-                                    * with the registered handles. */
-    FDTYPE* pal_fds;
-    PAL_HANDLE* pal_handles;
-    int npals;
     int nread;
     int nwaiters;
+
+    int npals;
+    PAL_HANDLE* pal_handles;
+
     AEVENTTYPE event;
+    LISTP_TYPE(shim_epoll_item) fds; /* this list contains all the
+                                    * shim_epoll_item objects in correspondence
+                                    * with the registered handles. */
 };
 
 struct shim_mount;
 struct shim_qstr;
 struct shim_dentry;
 
-/* The epolls list links to the back field of the shim_epoll_fd structure
+/* The epolls list links to the back field of the shim_epoll_item structure
  */
 struct shim_handle {
     enum shim_handle_type type;
@@ -333,8 +333,8 @@ struct shim_handle {
     struct shim_dentry* dentry;
 
     /* If this handle is registered for any epoll handle, this list contains
-     * a shim_epoll_fd object in correspondence with the epoll handle. */
-    LISTP_TYPE(shim_epoll_fd) epolls;
+     * a shim_epoll_item object in correspondence with the epoll handle. */
+    LISTP_TYPE(shim_epoll_item) epolls;
 
     struct shim_qstr uri; /* URI representing this handle, it is not
                            * necessary to be set. */

+ 1 - 1
LibOS/shim/src/bookkeep/shim_handle.c

@@ -741,7 +741,7 @@ BEGIN_CP_FUNC(handle) {
         }
 
         if (hdl->type == TYPE_EPOLL)
-            DO_CP(epoll_fd, &hdl->info.epoll.fds, &new_hdl->info.epoll.fds);
+            DO_CP(epoll_item, &hdl->info.epoll.fds, &new_hdl->info.epoll.fds);
 
         INIT_LISTP(&new_hdl->epolls);
 

+ 179 - 158
LibOS/shim/src/sys/shim_epoll.c

@@ -34,36 +34,29 @@
 
 /* Avoid duplicated definitions */
 #ifndef EPOLLIN
-
 #define EPOLLIN     0x001
-#define EPOLLPRI    0x002
 #define EPOLLOUT    0x004
 #define EPOLLRDNORM 0x040
-#define EPOLLRDBAND 0x080
 #define EPOLLWRNORM 0x100
-#define EPOLLERBAND 0x200
 #define EPOLLERR    0x008
 #define EPOLLHUP    0x010
 #define EPOLLRDHUP  0x2000
-
 #endif
 
-#define MAX_EPOLL_FDS 1024
+/* TODO: 1024 handles/FDs is a small number for high-load servers (e.g., Linux has ~3M) */
+#define MAX_EPOLL_HANDLES 1024
 
 struct shim_mount epoll_builtin_fs;
 
-/* shim_epoll_fds are linked as a list (by the list field),
- * hanging off of a shim_epoll_handle (by the fds field) */
-struct shim_epoll_fd {
+struct shim_epoll_item {
     FDTYPE fd;
-    unsigned int events;
     __u64 data;
+    unsigned int events;
     unsigned int revents;
-    struct shim_handle* handle;
-    struct shim_handle* epoll;
-    PAL_HANDLE pal_handle;
-    LIST_TYPE(shim_epoll_fd) list;
-    LIST_TYPE(shim_epoll_fd) back;
+    struct shim_handle* handle;      /* reference to monitored object (socket, pipe, file, etc) */
+    struct shim_handle* epoll;       /* reference to epoll object that monitors handle object */
+    LIST_TYPE(shim_epoll_item) list; /* list of shim_epoll_items, used by epoll object (via `fds`) */
+    LIST_TYPE(shim_epoll_item) back; /* list of epolls, used by handle object (via `epolls`) */
 };
 
 int shim_do_epoll_create1(int flags) {
@@ -78,10 +71,11 @@ int shim_do_epoll_create1(int flags) {
 
     hdl->type = TYPE_EPOLL;
     set_handle_fs(hdl, &epoll_builtin_fs);
-    epoll->maxfds      = MAX_EPOLL_FDS;
-    epoll->nfds        = 0;
-    epoll->pal_fds     = malloc(sizeof(FDTYPE) * MAX_EPOLL_FDS);
-    epoll->pal_handles = malloc(sizeof(PAL_HANDLE) * MAX_EPOLL_FDS);
+    epoll->maxfds      = MAX_EPOLL_HANDLES;
+    epoll->npals       = 0;
+    epoll->nread       = 0;
+    epoll->nwaiters    = 0;
+    epoll->pal_handles = malloc(sizeof(PAL_HANDLE) * MAX_EPOLL_HANDLES);
     create_event(&epoll->event);
     INIT_LISTP(&epoll->fds);
 
@@ -99,59 +93,59 @@ int shim_do_epoll_create(int size) {
 }
 
 static void update_epoll(struct shim_epoll_handle* epoll) {
-    struct shim_epoll_fd* tmp;
-    int npals    = 0;
+    struct shim_epoll_item* tmp;
+    epoll->npals = 0;
     epoll->nread = 0;
 
     LISTP_FOR_EACH_ENTRY(tmp, &epoll->fds, list) {
-        if (!tmp->pal_handle)
+        if (!tmp->handle->pal_handle)
             continue;
 
         debug("found handle %p (pal handle %p) from epoll handle %p\n", tmp->handle,
-              tmp->pal_handle, epoll);
+              tmp->handle->pal_handle, epoll);
 
-        epoll->pal_fds[npals]     = tmp->fd;
-        epoll->pal_handles[npals] = tmp->pal_handle;
-        npals++;
+        epoll->pal_handles[epoll->npals++] = tmp->handle->pal_handle;
         if (tmp->handle->acc_mode & MAY_READ)
             epoll->nread++;
     }
 
-    epoll->npals = npals;
-
+    /* if other threads are currently waiting on epoll_wait(), send a signal to update their
+     * epoll items (note that we send nwaiters number of signals -- to each waiting thread) */
     if (epoll->nwaiters)
         set_event(&epoll->event, epoll->nwaiters);
 }
 
 int delete_from_epoll_handles(struct shim_handle* handle) {
+    /* handle may be registered in several epolls, delete it from all of them via handle->epolls */
     while (1) {
+        /* first, get any epoll-item from this handle (via `back` list) and delete it from `back` */
         lock(&handle->lock);
-
         if (LISTP_EMPTY(&handle->epolls)) {
             unlock(&handle->lock);
             break;
         }
 
-        struct shim_epoll_fd* epoll_fd =
-            LISTP_FIRST_ENTRY(&handle->epolls, struct shim_epoll_fd, back);
+        struct shim_epoll_item* epoll_item =
+            LISTP_FIRST_ENTRY(&handle->epolls, struct shim_epoll_item, back);
 
-        LISTP_DEL(epoll_fd, &handle->epolls, back);
+        LISTP_DEL(epoll_item, &handle->epolls, back);
         unlock(&handle->lock);
 
-        struct shim_handle* epoll_hdl   = epoll_fd->epoll;
-        struct shim_epoll_handle* epoll = &epoll_hdl->info.epoll;
+        /* second, get epoll to which this epoll-item belongs to, and remove epoll-item from
+         * epoll's `fds` list, and trigger update_epoll() to re-populate pal_handles */
+        struct shim_handle* hdl         = epoll_item->epoll;
+        struct shim_epoll_handle* epoll = &hdl->info.epoll;
 
-        debug("delete handle %p from epoll handle %p\n", handle, &epoll_hdl->info.epoll);
-
-        lock(&epoll_hdl->lock);
-
-        LISTP_DEL(epoll_fd, &epoll->fds, list);
-        free(epoll_fd);
+        lock(&hdl->lock);
+        LISTP_DEL(epoll_item, &epoll->fds, list);
+        update_epoll(epoll);
+        unlock(&hdl->lock);
 
-        epoll_hdl->info.epoll.nfds--;
-        update_epoll(&epoll_hdl->info.epoll);
-        unlock(&epoll_hdl->lock);
-        put_handle(epoll_hdl);
+        /* finally, free this epoll-item and put reference to epoll it belonged to
+         * (note that epoll is deleted only after all handles referring to this epoll are
+         * deleted from it, so we keep track of this via refcounting) */
+        free(epoll_item);
+        put_handle(hdl);
     }
 
     return 0;
@@ -161,6 +155,9 @@ int shim_do_epoll_ctl(int epfd, int op, int fd, struct __kernel_epoll_event* eve
     struct shim_thread* cur = get_cur_thread();
     int ret                 = 0;
 
+    if (epfd == fd)
+        return -EINVAL;
+
     struct shim_handle* epoll_hdl = get_fd_handle(epfd, NULL, cur->handle_map);
     if (!epoll_hdl)
         return -EBADF;
@@ -170,14 +167,14 @@ int shim_do_epoll_ctl(int epfd, int op, int fd, struct __kernel_epoll_event* eve
     }
 
     struct shim_epoll_handle* epoll = &epoll_hdl->info.epoll;
-    struct shim_epoll_fd* epoll_fd;
+    struct shim_epoll_item* epoll_item;
 
     lock(&epoll_hdl->lock);
 
     switch (op) {
         case EPOLL_CTL_ADD: {
-            LISTP_FOR_EACH_ENTRY(epoll_fd, &epoll->fds, list) {
-                if (epoll_fd->fd == fd) {
+            LISTP_FOR_EACH_ENTRY(epoll_item, &epoll->fds, list) {
+                if (epoll_item->fd == fd) {
                     ret = -EEXIST;
                     goto out;
                 }
@@ -188,12 +185,13 @@ int shim_do_epoll_ctl(int epfd, int op, int fd, struct __kernel_epoll_event* eve
                 ret = -EBADF;
                 goto out;
             }
+            /* note that pipe and socket may not have pal_handle yet (e.g. before bind()) */
             if ((hdl->type != TYPE_PIPE && hdl->type != TYPE_SOCK) || !hdl->pal_handle) {
                 ret = -EPERM;
                 put_handle(hdl);
                 goto out;
             }
-            if (epoll->nfds == MAX_EPOLL_FDS) {
+            if (epoll->npals == MAX_EPOLL_HANDLES) {
                 ret = -ENOSPC;
                 put_handle(hdl);
                 goto out;
@@ -201,34 +199,36 @@ int shim_do_epoll_ctl(int epfd, int op, int fd, struct __kernel_epoll_event* eve
 
             debug("add handle %p to epoll handle %p\n", hdl, epoll);
 
-            epoll_fd             = malloc(sizeof(struct shim_epoll_fd));
-            epoll_fd->fd         = fd;
-            epoll_fd->events     = event->events;
-            epoll_fd->data       = event->data;
-            epoll_fd->revents    = 0;
-            epoll_fd->handle     = hdl;
-            epoll_fd->epoll      = epoll_hdl;
-            epoll_fd->pal_handle = hdl->pal_handle;
-
-            /* Register the epoll handle */
+            epoll_item             = malloc(sizeof(struct shim_epoll_item));
+            epoll_item->fd         = fd;
+            epoll_item->events     = event->events;
+            epoll_item->data       = event->data;
+            epoll_item->revents    = 0;
+            epoll_item->handle     = hdl;
+            epoll_item->epoll      = epoll_hdl;
             get_handle(epoll_hdl);
+
+            /* register hdl (corresponding to FD) in epoll (corresponding to EPFD):
+             * - bind hdl to epoll-item via the `back` list
+             * - bind epoll-item to epoll via the `list` list */
             lock(&hdl->lock);
-            INIT_LIST_HEAD(epoll_fd, back);
-            LISTP_ADD_TAIL(epoll_fd, &hdl->epolls, back);
+            INIT_LIST_HEAD(epoll_item, back);
+            LISTP_ADD_TAIL(epoll_item, &hdl->epolls, back);
             unlock(&hdl->lock);
-            put_handle(hdl);
 
-            INIT_LIST_HEAD(epoll_fd, list);
-            LISTP_ADD_TAIL(epoll_fd, &epoll->fds, list);
-            epoll->nfds++;
+            /* note that we already grabbed epoll_hdl->lock so can safely update epoll */
+            INIT_LIST_HEAD(epoll_item, list);
+            LISTP_ADD_TAIL(epoll_item, &epoll->fds, list);
+
+            put_handle(hdl);
             goto update;
         }
 
         case EPOLL_CTL_MOD: {
-            LISTP_FOR_EACH_ENTRY(epoll_fd, &epoll->fds, list) {
-                if (epoll_fd->fd == fd) {
-                    epoll_fd->events = event->events;
-                    epoll_fd->data   = event->data;
+            LISTP_FOR_EACH_ENTRY(epoll_item, &epoll->fds, list) {
+                if (epoll_item->fd == fd) {
+                    epoll_item->events = event->events;
+                    epoll_item->data   = event->data;
                     goto update;
                 }
             }
@@ -238,22 +238,22 @@ int shim_do_epoll_ctl(int epfd, int op, int fd, struct __kernel_epoll_event* eve
         }
 
         case EPOLL_CTL_DEL: {
-            LISTP_FOR_EACH_ENTRY(epoll_fd, &epoll->fds, list) {
-                if (epoll_fd->fd == fd) {
-                    struct shim_handle* hdl = epoll_fd->handle;
+            LISTP_FOR_EACH_ENTRY(epoll_item, &epoll->fds, list) {
+                if (epoll_item->fd == fd) {
+                    struct shim_handle* hdl = epoll_item->handle;
 
-                    /* Unregister the epoll handle */
+                    /* unregister hdl (corresponding to FD) in epoll (corresponding to EPFD):
+                     * - unbind hdl from epoll-item via the `back` list
+                     * - unbind epoll-item from epoll via the `list` list */
                     lock(&hdl->lock);
-                    LISTP_DEL(epoll_fd, &hdl->epolls, back);
+                    LISTP_DEL(epoll_item, &hdl->epolls, back);
                     unlock(&hdl->lock);
 
-                    debug("delete handle %p from epoll handle %p\n", hdl, epoll);
+                    /* note that we already grabbed epoll_hdl->lock so can safely update epoll */
+                    LISTP_DEL(epoll_item, &epoll->fds, list);
 
                     put_handle(epoll_hdl);
-
-                    LISTP_DEL(epoll_fd, &epoll->fds, list);
-                    epoll->nfds--;
-                    free(epoll_fd);
+                    free(epoll_item);
                     goto update;
                 }
             }
@@ -263,7 +263,7 @@ int shim_do_epoll_ctl(int epfd, int op, int fd, struct __kernel_epoll_event* eve
         }
 
         default:
-            ret = -ENOSYS;
+            ret = -EINVAL;
             goto out;
     }
 
@@ -277,7 +277,12 @@ out:
 
 int shim_do_epoll_wait(int epfd, struct __kernel_epoll_event* events, int maxevents,
                        int timeout_ms) {
-    int ret                       = 0;
+    if (maxevents <= 0)
+        return -EINVAL;
+
+    if (!events || test_user_memory(events, sizeof(*events) * maxevents, true))
+        return -EFAULT;
+
     struct shim_handle* epoll_hdl = get_fd_handle(epfd, NULL, NULL);
     if (!epoll_hdl)
         return -EBADF;
@@ -287,85 +292,97 @@ int shim_do_epoll_wait(int epfd, struct __kernel_epoll_event* events, int maxeve
     }
 
     struct shim_epoll_handle* epoll = &epoll_hdl->info.epoll;
-    struct shim_epoll_fd* epoll_fd;
-    int nevents = 0;
-    int npals, nread;
     bool need_update = false;
 
     lock(&epoll_hdl->lock);
-retry:
-    if (!(npals = epoll->npals))
-        goto reply;
 
-    PAL_HANDLE* pal_handles = __alloca(sizeof(PAL_HANDLE) * (npals + 1));
-    FDTYPE* fds             = __alloca(sizeof(FDTYPE) * npals);
-    memcpy(fds, epoll->pal_fds, sizeof(FDTYPE) * npals);
-    memcpy(pal_handles, epoll->pal_handles, sizeof(PAL_HANDLE) * npals);
-    pal_handles[npals] = epoll->event.event;
+    int npals = epoll->npals;
+    while (npals) {
+        /* wait on epoll's PAL handles + one "event" handle that signals epoll updates */
+        PAL_HANDLE* pal_handles = malloc((npals + 1) * sizeof(PAL_HANDLE));
+        if (!pal_handles)
+            return -ENOMEM;
 
-    if ((nread = epoll->nread))
-        epoll->nwaiters++;
+        memcpy(pal_handles, epoll->pal_handles, npals * sizeof(PAL_HANDLE));
+        pal_handles[npals] = epoll->event.event;
 
-    unlock(&epoll_hdl->lock);
+        epoll->nwaiters++;  /* mark epoll as being waited on (so epoll-update signal is sent) */
+        unlock(&epoll_hdl->lock);
 
-    PAL_NUM pal_timeout = timeout_ms == -1 ? NO_TIMEOUT : (PAL_NUM)timeout_ms * 1000;
-    PAL_HANDLE polled =
-        DkObjectsWaitAny(nread ? npals + 1 : npals, pal_handles, nread ? pal_timeout : 0);
+        PAL_NUM pal_timeout = timeout_ms == -1 ? NO_TIMEOUT : (PAL_NUM)timeout_ms * 1000;
+        if (!epoll->nread) {
+            /* special case: epoll doesn't contain a single handle with MAY_READ, thus there are
+             * only write events possible, and for this we don't wait but return immediately
+             * TODO: this is an ugly corner case which may backfire */
+            pal_timeout = 0;
+        }
 
-    lock(&epoll_hdl->lock);
+        /* TODO: This is highly inefficient, since DkObjectsWaitAny returns only one (random)
+         *       handle out of the whole array of handles-waiting-for-events. We must replace
+         *       this with DkObjectsWaitEvents(). */
+        PAL_HANDLE polled = DkObjectsWaitAny(npals + 1, pal_handles, pal_timeout);
 
-    if (nread)
+        lock(&epoll_hdl->lock);
         epoll->nwaiters--;
+        free(pal_handles);
 
-    if (!polled)
-        goto reply;
-
-    if (polled == epoll->event.event) {
-        wait_event(&epoll->event);
-        goto retry;
-    }
-
-    PAL_STREAM_ATTR attr;
-    if (!DkStreamAttributesQueryByHandle(polled, &attr))
-        goto reply;
+        if (polled == epoll->event.event) {
+            wait_event(&epoll->event);
+            npals = epoll->npals; /* epoll was updated, probably npals is new */
+            continue;
+        }
 
-    LISTP_FOR_EACH_ENTRY(epoll_fd, &epoll->fds, list) {
-        if (polled == epoll_fd->pal_handle) {
-            debug("epoll: fd %d (handle %p) polled\n", epoll_fd->fd, epoll_fd->handle);
+        PAL_STREAM_ATTR attr;
+        if (!polled || !DkStreamAttributesQueryByHandle(polled, &attr))
+            break;
 
-            if (attr.disconnected) {
-                epoll_fd->revents |= EPOLLERR | EPOLLHUP | EPOLLRDHUP;
-                epoll_fd->pal_handle = NULL;
-                need_update          = true;
+        struct shim_epoll_item* epoll_item = NULL;
+        struct shim_epoll_item* tmp;
+        LISTP_FOR_EACH_ENTRY(tmp, &epoll->fds, list) {
+            if (polled == tmp->handle->pal_handle) {
+                epoll_item = tmp;
+                break;
             }
-            if (attr.readable)
-                epoll_fd->revents |= EPOLLIN;
-            if (attr.writable)
-                epoll_fd->revents |= EPOLLOUT;
-            break;
         }
+
+        /* found epoll item that was polled, update its revents according to attr */
+        assert(epoll_item);
+        if (attr.disconnected) {
+            epoll_item->revents |= EPOLLERR | EPOLLHUP | EPOLLRDHUP;
+            epoll_item->handle   = NULL;
+            need_update        = true; /* handle disconnected, need to remove from epoll list */
+        }
+        if (attr.readable)
+            epoll_item->revents |= EPOLLIN | EPOLLRDNORM;
+        if (attr.writable)
+            epoll_item->revents |= EPOLLOUT | EPOLLWRNORM;
+
+        npals = 0; /* to exit the while loop */
     }
 
-reply:
-    LISTP_FOR_EACH_ENTRY(epoll_fd, &epoll->fds, list) {
+    /* update user-supplied events array with all events detected till now on epoll */
+    int nevents = 0;
+    struct shim_epoll_item* epoll_item;
+    LISTP_FOR_EACH_ENTRY(epoll_item, &epoll->fds, list) {
         if (nevents == maxevents)
             break;
 
-        if ((epoll_fd->events | EPOLLERR | EPOLLHUP) & epoll_fd->revents) {
-            events[nevents].events = (epoll_fd->events | EPOLLERR | EPOLLHUP) & epoll_fd->revents;
-            events[nevents].data   = epoll_fd->data;
+        unsigned int monitored_events = epoll_item->events | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
+        if (epoll_item->revents & monitored_events) {
+            events[nevents].events = epoll_item->revents & monitored_events;
+            events[nevents].data   = epoll_item->data;
+            epoll_item->revents &= ~epoll_item->events; /* informed user about revents, may clear */
             nevents++;
-            epoll_fd->revents &= ~epoll_fd->events;
         }
     }
 
+    /* some handles were disconnected and thus must be removed from the epoll list */
     if (need_update)
         update_epoll(epoll);
 
     unlock(&epoll_hdl->lock);
-    ret = nevents;
     put_handle(epoll_hdl);
-    return ret;
+    return nevents;
 }
 
 int shim_do_epoll_pwait(int epfd, struct __kernel_epoll_event* events, int maxevents,
@@ -377,7 +394,13 @@ int shim_do_epoll_pwait(int epfd, struct __kernel_epoll_event* events, int maxev
 }
 
 static int epoll_close(struct shim_handle* hdl) {
-    __UNUSED(hdl);
+    struct shim_epoll_handle* epoll = &hdl->info.epoll;
+
+    free(epoll->pal_handles);
+    destroy_event(&epoll->event);
+
+    /* epoll is finally closed only after all FDs referring to it have been closed */
+    assert(LISTP_EMPTY(&epoll->fds));
     return 0;
 }
 
@@ -390,53 +413,51 @@ struct shim_mount epoll_builtin_fs = {
     .fs_ops = &epoll_fs_ops,
 };
 
-BEGIN_CP_FUNC(epoll_fd) {
+BEGIN_CP_FUNC(epoll_item) {
     __UNUSED(size);
-    assert(size == sizeof(LISTP_TYPE(shim_epoll_fd)));
+    assert(size == sizeof(LISTP_TYPE(shim_epoll_item)));
 
-    LISTP_TYPE(shim_epoll_fd)* old_list = (LISTP_TYPE(shim_epoll_fd)*)obj;
-    LISTP_TYPE(shim_epoll_fd)* new_list = (LISTP_TYPE(shim_epoll_fd)*)objp;
-    struct shim_epoll_fd* epoll_fd;
+    LISTP_TYPE(shim_epoll_item)* old_list = (LISTP_TYPE(shim_epoll_item)*)obj;
+    LISTP_TYPE(shim_epoll_item)* new_list = (LISTP_TYPE(shim_epoll_item)*)objp;
+    struct shim_epoll_item* epoll_item;
 
     debug("checkpoint epoll: %p -> %p (base = 0x%08lx)\n", old_list, new_list, base);
 
     INIT_LISTP(new_list);
 
-    LISTP_FOR_EACH_ENTRY(epoll_fd, old_list, list) {
-        ptr_t off = ADD_CP_OFFSET(sizeof(struct shim_epoll_fd));
+    LISTP_FOR_EACH_ENTRY(epoll_item, old_list, list) {
+        ptr_t off = ADD_CP_OFFSET(sizeof(struct shim_epoll_item));
 
-        struct shim_epoll_fd* new_epoll_fd = (struct shim_epoll_fd*)(base + off);
+        struct shim_epoll_item* new_epoll_item = (struct shim_epoll_item*)(base + off);
 
-        new_epoll_fd->fd         = epoll_fd->fd;
-        new_epoll_fd->events     = epoll_fd->events;
-        new_epoll_fd->data       = epoll_fd->data;
-        new_epoll_fd->revents    = epoll_fd->revents;
-        new_epoll_fd->pal_handle = NULL;
+        new_epoll_item->fd         = epoll_item->fd;
+        new_epoll_item->events     = epoll_item->events;
+        new_epoll_item->data       = epoll_item->data;
+        new_epoll_item->revents    = epoll_item->revents;
 
-        LISTP_ADD(new_epoll_fd, new_list, list);
+        LISTP_ADD(new_epoll_item, new_list, list);
 
-        DO_CP(handle, epoll_fd->handle, &new_epoll_fd->handle);
+        DO_CP(handle, epoll_item->handle, &new_epoll_item->handle);
     }
 
     ADD_CP_FUNC_ENTRY((ptr_t)objp - base);
 }
-END_CP_FUNC(epoll_fd)
+END_CP_FUNC(epoll_item)
 
-BEGIN_RS_FUNC(epoll_fd) {
+BEGIN_RS_FUNC(epoll_item) {
     __UNUSED(offset);
-    LISTP_TYPE(shim_epoll_fd)* list = (void*)(base + GET_CP_FUNC_ENTRY());
-    struct shim_epoll_fd* epoll_fd;
+    LISTP_TYPE(shim_epoll_item)* list = (void*)(base + GET_CP_FUNC_ENTRY());
+    struct shim_epoll_item* epoll_item;
 
     CP_REBASE(*list);
 
-    LISTP_FOR_EACH_ENTRY(epoll_fd, list, list) {
-        CP_REBASE(epoll_fd->handle);
-        CP_REBASE(epoll_fd->back);
-        epoll_fd->pal_handle = epoll_fd->handle->pal_handle;
-        CP_REBASE(epoll_fd->list);
+    LISTP_FOR_EACH_ENTRY(epoll_item, list, list) {
+        CP_REBASE(epoll_item->handle);
+        CP_REBASE(epoll_item->back);
+        CP_REBASE(epoll_item->list);
 
-        DEBUG_RS("fd=%d,path=%s,type=%s,uri=%s", epoll_fd->fd, qstrgetstr(&epoll_fd->handle->path),
-                 epoll_fd->handle->fs_type, qstrgetstr(&epoll_fd->handle->uri));
+        DEBUG_RS("fd=%d,path=%s,type=%s,uri=%s", epoll_item->fd, qstrgetstr(&epoll_item->handle->path),
+                 epoll_item->handle->fs_type, qstrgetstr(&epoll_item->handle->uri));
     }
 }
-END_RS_FUNC(epoll_fd)
+END_RS_FUNC(epoll_item)