Commit 521e032
committed
Fix epoll_ctl dropping registrations in multi-threaded guests
In a multi-threaded guest host_fd_ref_open() hands back a dup of the
target fd that host_fd_ref_close() closes when the syscall returns.
sys_epoll_ctl() used that transient dup as the kqueue knote ident, and
the kernel drops a knote the moment its fd is closed -- so every epoll
registration made while multi-threaded was torn down the instant
epoll_ctl() returned, and epoll_pwait() never reported readiness again.
Single-threaded guests borrow the raw fd (no dup, no close) and never
hit it. Node's libuv DelayedTaskScheduler (eventfd + epoll backing
uv_async_send) relied on this path and hung forever at process exit:
the main thread blocked in WorkerThreadsTaskRunner::Shutdown ->
uv_thread_join on a scheduler thread that could no longer be woken.
Key the knote on the persistent host fd from the fd table. Take it from
the same atomic fd_snapshot() that validates the fd, so the ident comes
from the entry that was validated rather than a second fd_to_host()
lookup that could race a concurrent close/reopen. Result mapping already
uses udata (the guest fd), so the ident only needs to stay open and
refer to the same open file description.
Guard the close+reopen ABA with a per-slot generation counter. fd_table
entries now carry a monotonic generation bumped on every allocation;
epoll registrations stamp it at ADD/MOD. If the guest closes a watched
fd and reopens it (reusing the guest fd number), the kernel has already
dropped the original knote, yet reg->active still looks live -- a later
DEL/MOD would EV_DELETE the wrong knote on the reused host fd. A
mismatched generation now marks the registration gone, so DEL/MOD report
ENOENT (matching Linux's auto-removal on close) and ADD starts fresh.
Also implement the FIONBIO / FIOCLEX / FIONCLEX ioctls, which were
falling through to ENOTTY. libuv's uv_pipe_open() sets non-blocking via
FIONBIO, so Node's console.log() to a pipe threw "open ENOTTY". FIONBIO
maps to F_SETFL O_NONBLOCK (status flag, shared across the dup).
FIOCLEX/FIONCLEX mirror F_SETFD by toggling the fd_table cloexec bit
rather than the host fd's FD_CLOEXEC, which is per-descriptor and lost on
the dup. They need no host fd, so they dispatch before
host_fd_ref_open_regular_io() -- which rejects O_PATH (FD_PATH) with
EBADF, while Linux allows these ioctls (like F_SETFD) on O_PATH fds --
and validate the slot and flip the flag in a single fd_lock section, so
there is no validate-then-mutate window for a concurrent close/reuse to
flip cloexec on a different file.
Add tests/test-epoll-mt.c: a CLONE_THREAD sibling keeps the guest
multi-threaded across epoll_ctl, then asserts a registered eventfd and
pipe still deliver an EPOLLIN edge. It fails without the poll.c fix.
Add tests/test-ioctl-cloexec.c covering FIOCLEX/FIONCLEX round-trip on
both a regular and an O_PATH fd. Both are listed in tests/manifest.txt
so the driver runs them under make check.
With these, node:alpine (node v26.3.0) runs JavaScript, timers, the
libuv threadpool, and promises, and exits cleanly.1 parent 23b8300 commit 521e032
7 files changed
Lines changed: 539 additions & 17 deletions
File tree
- src/syscall
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
352 | 352 | | |
353 | 353 | | |
354 | 354 | | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
355 | 358 | | |
356 | 359 | | |
357 | 360 | | |
| |||
705 | 708 | | |
706 | 709 | | |
707 | 710 | | |
708 | | - | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
709 | 715 | | |
710 | 716 | | |
711 | 717 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1476 | 1476 | | |
1477 | 1477 | | |
1478 | 1478 | | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
| 1500 | + | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
1479 | 1506 | | |
1480 | 1507 | | |
1481 | 1508 | | |
| |||
1688 | 1715 | | |
1689 | 1716 | | |
1690 | 1717 | | |
| 1718 | + | |
| 1719 | + | |
| 1720 | + | |
| 1721 | + | |
| 1722 | + | |
| 1723 | + | |
| 1724 | + | |
| 1725 | + | |
| 1726 | + | |
| 1727 | + | |
| 1728 | + | |
| 1729 | + | |
| 1730 | + | |
| 1731 | + | |
| 1732 | + | |
| 1733 | + | |
| 1734 | + | |
| 1735 | + | |
| 1736 | + | |
| 1737 | + | |
| 1738 | + | |
| 1739 | + | |
| 1740 | + | |
1691 | 1741 | | |
1692 | 1742 | | |
1693 | 1743 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
694 | 694 | | |
695 | 695 | | |
696 | 696 | | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
697 | 702 | | |
698 | 703 | | |
699 | 704 | | |
| |||
781 | 786 | | |
782 | 787 | | |
783 | 788 | | |
784 | | - | |
785 | | - | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
786 | 803 | | |
787 | 804 | | |
788 | 805 | | |
| 806 | + | |
789 | 807 | | |
790 | 808 | | |
791 | 809 | | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
792 | 823 | | |
793 | 824 | | |
794 | 825 | | |
795 | | - | |
796 | 826 | | |
797 | 827 | | |
798 | 828 | | |
| |||
804 | 834 | | |
805 | 835 | | |
806 | 836 | | |
807 | | - | |
| 837 | + | |
808 | 838 | | |
809 | 839 | | |
810 | 840 | | |
811 | 841 | | |
812 | | - | |
| 842 | + | |
813 | 843 | | |
814 | 844 | | |
815 | 845 | | |
| |||
819 | 849 | | |
820 | 850 | | |
821 | 851 | | |
822 | | - | |
823 | 852 | | |
824 | 853 | | |
825 | 854 | | |
| |||
829 | 858 | | |
830 | 859 | | |
831 | 860 | | |
832 | | - | |
833 | 861 | | |
834 | 862 | | |
835 | 863 | | |
836 | 864 | | |
837 | | - | |
838 | 865 | | |
839 | 866 | | |
840 | 867 | | |
841 | 868 | | |
842 | 869 | | |
843 | 870 | | |
844 | 871 | | |
845 | | - | |
846 | 872 | | |
847 | 873 | | |
848 | 874 | | |
| |||
860 | 886 | | |
861 | 887 | | |
862 | 888 | | |
863 | | - | |
| 889 | + | |
864 | 890 | | |
865 | 891 | | |
866 | 892 | | |
867 | | - | |
| 893 | + | |
868 | 894 | | |
869 | 895 | | |
870 | 896 | | |
| |||
894 | 920 | | |
895 | 921 | | |
896 | 922 | | |
897 | | - | |
| 923 | + | |
898 | 924 | | |
899 | 925 | | |
900 | 926 | | |
901 | 927 | | |
902 | | - | |
| 928 | + | |
903 | 929 | | |
904 | 930 | | |
905 | 931 | | |
906 | 932 | | |
907 | 933 | | |
908 | 934 | | |
909 | | - | |
910 | 935 | | |
911 | 936 | | |
912 | 937 | | |
913 | 938 | | |
914 | 939 | | |
915 | 940 | | |
916 | | - | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
917 | 944 | | |
918 | 945 | | |
919 | 946 | | |
| 947 | + | |
920 | 948 | | |
921 | 949 | | |
922 | 950 | | |
923 | | - | |
924 | 951 | | |
925 | 952 | | |
926 | 953 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| 65 | + | |
| 66 | + | |
65 | 67 | | |
66 | 68 | | |
| 69 | + | |
67 | 70 | | |
68 | 71 | | |
69 | 72 | | |
| |||
0 commit comments