As Phillip's answer said, all the answers were basically up to how you design your execution model, there are various tradeoffs between different execution model. That said, if you're modeling your execution model similar to JavaScript, there are a couple things we do know with JavaScript.
JavaScript uses an execution model that boils down to single threaded operation with an event queue. At the heart of this is the event queue, which is implemented using a priority queue with scheduled time as the priority/sorting key and an infinite loop that pops items off the priority queue called the event loop (sometimes also called trampoline). A priority queue is just like regular queue, except you don't just push items to the back of the queue, but you insert the item in their position as determined by the sorting key. Efficient implementation of priority queue usually uses either a heap data structure, a tree, or skip list to maintain partial sorting without having to actually constantly re-sort the queue as items gets pushed and popped into the queue very frequently.
The event loop is basically just an infinite loop that peeks at the scheduled execution time of the item at the front of the queue and optionally sleeps until the scheduled time, when it returns from sleeping, it pops the front of the queue and executes its callback, this repeats forever until the loop is closed. Any of the callback can push item to the queue, either to be executed "immediately" (i.e. it's pushed with scheduled time that immediately expires, so it'll run after all the other events that has also expired), or with future scheduled time such as when using setTimeout()
/setInterval()
with non-zero time.
Additionally, there are also hardware events like mouse clicks, typing into the keyboard, network events, and filesystem events, that may also schedule items into the queue asynchronously; in this case, the event queue may have to handle an interrupted sleep, respond to the hardware event, and then reschedule another sleep. Also, in some languages, the execution model may also have a mechanism to specify the priority of events, so higher priority tasks always gets precedence over lower priority tasks that expires at the same time.
The call stack is implemented, unsurprisingly, using a stack data structure, containing local variable contexts and any other information needed to resume when returning from a function call. There's the simple stack data structure that you might have been taught at CompSci classes, but you probably are also hardware stack that allows your CPU to return from a function call opcode. Depending on the design of your language, you may want to use either a hardware or software stack.
The basic principle between hardware and software stack are basically the same, you push and pop item to the top of the stack. Whenever you call a function, you push a new local variable contexts to the stack and the return address, and whenever you return from a function you pop off the top of the stack and jump into the return address. The only main difference is that with hardware stack you have to use the low level CPU instructions which will manage the call stack implicitly and automatically.
JavaScript execution model is single threaded, which means that a single JavaScript execution context is allocated a single real OS thread. Recent version of JavaScript also has async functions/coroutines which mimicks the execution of a thread, so the language can track multiple threads of execution without using real OS thread and the overhead associated with real context switching. This is also called green threading.
At the most basic level, coroutines just means that you're switching the current call stack's base pointer without actually doing a full thread context switching (which involves saving state of the CPU registers and setting up a bunch of hardware timer interrupts to preempt the thread if it didn't yield the execution).
Without coroutines, a single OS thread usually have a single hardware stack, and languages that uses single threaded execution model uses the event loop to trampoline the concurrent execution between multiple callbacks. With green threads/coroutines, that trampoline will also switch the call stacks.