> you cannot await in a sync function
In C# it’s easy to block the current thread waiting for an async task to complete, see Task.Wait method.
> since it will never resolve, you can also never await it
In C#, awaiting for things which never complete is not that bad, the standard library has Task.WhenAny() method for that.
> let's talk about C#. Here the origin story is once again entirely different
Originally, NT kernel was designed for SMP from the ground up, supports asynchronous operations on handles like files and sockets, and since NT 3.5 the kernel includes support for thread pool to dispatch IO completions: https://en.wikipedia.org/wiki/Input/output_completion_port
Overlapped I/O and especially IOCP are hard to use directly. When Microsoft designed initial version of .NET, they implemented thread pool and IOCP inside the runtime, and exposed higher-level APIs to use them. Stuff like Stream.BeginRead / Stream.EndRead available since .NET 1.1 in 2003, the design pattern is called Asynchronous Programming Model (APM).
Async/await language feature introduced in .NET 4.5 in 2012 is a thin layer of sugar on top of these begin/end asynchronous APIs which were always there. BTW, if you have a pair of begin/end methods, converting into async/await takes 1 line of code, see TaskFactory.FromAsync.