I am using an inhouse developed multi tasking scheduler for 8051. Every function that I write, I need to put reentrant on it. Is it possible to add a compiler directive like the c166 compilers for c51 compiler?
Any real implementation of a multithreading OS needs to address the static data usage of the CLib. You must either use only pure functions implemented with registers and stack-allocated locals, or you use indirect addressing for the static data storage of all C lib functions, and supply a different static storage area for each thread. The compiler must be thread-aware, or allow you to reimplement static storage allocator functions for the CLib to be really functional in this architecture. When you can't do that, context switch is costly and you have to surround the CLib with access locks to prevent static clash. That is precisely what happens in the 8051.
Moreover, in the 8051, particularly in Keil C, the default storage class is overlay for local data. This is faster and generates smaller footprint code, but requires a single-threaded architecture, of course, for the compiler to perform static analysis on the code.
The alternative approach is to force the shared functions to be reentrant, i.e., force the default storage class of locals to be allocated on a stack.
On the 8051 this cost is excessive. I know of no small CLib for the '51 that is fully reentrant by design, and it seems that such a library would be much heavier in size and speed when compared with a staggered clib.
I agree with erik malund, in that a cooperative, single_threaded_plus_interrupts architecture can generally be much faster than a true multithreaded architecture for the 8051. This is not just an aesthetic choice. The comparison of a well designed event-driven cooperative multitasking system with a preemptive RTOS-based system leaves little space for argument. Even for 8KB xdata devices running above 20MHz, the CPU bandwidth taken by the RTOS kernel is prohibitive.
For other cores, this is not necessarily true. The ARM, for example, is a core designed to be used in a multithreaded, multiprocessor architecture. And the RVCT libraries are designed in a way that allows you to reimplement the necessary base functions to support your own true multitasking system, in a very optimized and transparent way.
I agree totaly with Jonny and Eric on the advantage of single task system. I also understand the disadvantage of having reentrant functions. Unfortunately, I have to live with this limitation for the time being. Rather than adding the reentrant keyword on every function that is called from tasks, I was looking for a quick compiler directive that will do the trick. Just like c166 compiler.
Your problem may not be as bad as it seems. The Keil C Lib has many functions that are pure or reentrant. They are described in the clib documentation. Those functions are reentrant and thread-safe.
The clib non-reentrant fucntions are another pain. Your clear alternative for a better life would be not using the standard clib supplied functions that are not reentrant in your code. You can implement a version of those needed functions in a lib of yours, and the linker will use your version instead of the clib version. This has the advantage of total control, so if you can't write a pure registered function, you can at least use a tempdata static allocation that can be controlled by your task switcher. One very simple way to do this is to have a global pointer that points to the thread local static storage for your clib functions (your tempdata section). Whenever you switch contexts, you can set the pointer to the new thread local storage base address, and the threads will happily live oblivious of one another. This is MUCH faster to switch, and need no locks.
Your own functions are thread safe if they are pure (no explicit global vars and no static vars) and don't have memory temporary storage, i.e., all its vars are stored in banked registers. Again, if you can't write them small to fit banked registers, you can use the above indirect thread local storage pointer solution for your own functions. Since it is private to a single thread, you can use heavy overlaying to keep the footprint small.