Wednesday, May 25, 2005

Semi Pre-emptive Multithreading

Screens has a semi pre-emptive multi-threading scheduler. What is the difference? Single threading: PalmOS is actually pre-emptive but you can only have one application which has only one thread running. You cannot create threads however you can use the existing threads like the multimedia thread and the serial manager thread. Cooperative multi-threading: Windows 3.1 and MacOS up to version 9 are cooperative which means that you can have threads but they each thread must have points where it gives up (yields) control to the scheduler so that the next thread can be continued. This means that threads must call a specific yeild function at many intervals or otherwise it can starve the other threads in the system for CPU time. pre-emptive multi-threading: Windows 9x/XP/2003 and MacOS X are pre-emptive which means that you can have threads but the system forcefully yields threads instead of threads deciding when they want to share CPU time with other threads. semi pre-emptive multi-threading: Screens is semi pre-emptive which while in reality its cooperative in that the thread does the yielding, any API call can yield so as long as threads call API calls, the system can switch between threads. This gives the advantages of pre-emptive in that you dont need to structure your thread around yielding points but a simple for loop can still freeze the system. Why use the last method? Screens runs on top of PalmOS and it does not have access to the multi-threading API (only the system apps can). There are a few advantages of using semi pre-emptive multi-threading: 1. The threading actually happens in the module, so the threading is language and implementation independent. 2. You dont need to implement locks, semaphores or mutexes or deal with interupt problems. Screens does not use these. Because modules dont have dynamic memory, the sharable memory is the object storage and the object storage does the blocking of threads for you so that no two threads will read/write to the same object. So what is actually happening? The kernel (Screens Core) loops between threads depending on thier priority. When the kernel resumes a thread, it just calls the threads code application (prc file). The application then restores its stack from the object storage using DmFindDatabase and SysAppLaunch to do kernel API calls and jumps to the stack using ErrSetJump and ErrLongJump. When you do a kernel API call, it returns non 0 if the thread needs to save its stack and close down. Note that example code is given so developers dont need to do this, wrappers do it for them. Kernel calls are done using SysAppLaunch sub launching however most of the time function wrappers you call are doing a combination of kernel calls and might be doing a context switch. Developers do not have to worry about the swithing mecanism, just do API calls as normal, the example code does the rest. While calling a PalmOS function does block the kernel untill the function ends, the Screens API calls can yield to the kernel at any time.

No comments: