It really depends on the OS, but as far as I know, both Windows and all Unix-like systems primarily use polling (i.e. the kind of polling where the process sleeps waiting for a blocking system call to return – not the kind of polling where the process keeps checking repeatedly). Signal usage is rare.
In the most basic case, if the process wants to read synchronously from a single file handle, it will call read() or ReadFile() and the system call will block until data is available. (It might create several threads, each waiting for read() on a different file handle, but that's uncommon.)
With multiple sources, the process would call poll() or WaitForMultipleObjects(), which also blocks until some event and eventually returns one of the given file handles which the process could read() from.
When dealing with a large amount of sources, epoll or kqueue are preferred – I am not sure of the Windows equivalent; it might be IOCP or Overlapped I/O. (See also: the new io_uring API on Linux and the almost identical IoRing on Windows.)
Most larger programs are structured around a central "event loop" which will poll() on all sources, handle some events, then poll() again, repeat. For example, when you're using a web browser on Linux, two programs are involved:
the display server (such as Xorg for X11 or GNOME Shell for Wayland) has an event loop that polls for user input via /dev/input/* devices (from kernel) as well as application X11 or Wayland events via sockets (draw commands from graphical apps);
the browser has an event loop that polls for user input via its X11 or Wayland socket (from the display server) as well as network traffic from open sockets (e.g. active HTTP downloads).
There exist a few old "asynchronous I/O" APIs do use signals (the one from 4.2BSD, I believe?); setting the FASYNC flag will cause SIGIO to be sent; but overall it seems to be very rare. (And if a process is doing nothing but waiting to receive a signal, then it might as well just wait for a blocking poll() to return instead, without any of the hassle of signal handlers – especially without worrying about reentrancy or overflowing the signal queue...)
In fact, on Linux and FreeBSD, event-loop frameworks often choose to receive signals via polling – the program masks all signals from their normal delivery, then uses signalfd() to create a file handle that can be polled, and when a signal occurs a struct siginfo
can be read from the signalfd handle at the process' own leisure (the event loop is responsible for calling the signal handler). Similarly, timer events can be delivered through timerfd without relying on SIGALRM and such.