Is there a rule governing generation of RTX task ids OS_TID? It would be interesting to know:
a. if they are incremented sequentially, and b. if there is a max value for OS_TID
I am writing a lib which will cache some data in a buffer. That lib can be called from multiple tasks at the same time, so I want to keep separate buffers for each task. If OS_TID is deterministic then it will be a good differentiator for the per-task buffers.
Any other suggestions are welcome too.
Thanks
Regarding your suggested approach...</p>
I thought you were suggesting having separate memory block for each task that was going to use the library. I am not suggesting this at all. My suggestion was to just make the library thread safe and re-entrant.
Cumbersome because of the semantics of such an API. If I understood correctly, first you need define per-task buffer and then have the calling task pass in a pointer to that buffer to the function that actually wants to keep track of per-task data. E.g. in a logging API which likes to buffer some data before flushing to file, the calling task will have to pass in a pointer to its buffer to log() function. That creates unwanted dependencies and tight coupling between caller (task) and callee (log() function) - a fertile ground for breeding spaghetti code. Moreover, buffering is responsibility of callee. Why should the caller worry about it?
No, you did not understand at all. The application does not need any knowledge of how this is implemented. (My guess is that you probably had no clue the Keil was doing this for the C runtime library. IF they changed the API for the C run time library my guess is that you would have had a clue about this and thought they were insane for changing the interface. Only the library uses this buffer. When the library needs to use one of these per tasks buffers, it uses the TID to get a pointer to the buffer.
// Also in RTX_CM_Lib.n void *__user_perthread_libspace (void) { /* Provide a separate libspace for each task. */ uint32_t idx; idx = (os_running != 0U) ? runtask_id () : 0U; if (idx == 0U) { /* RTX not running yet. */ return (&__libspace_start); } return ((void *)&std_libspace[idx-1]); }
this function above returns the unique buffer associated with the task that called the library. The API for the library does not change.
// There is nothing extra to pass in printf() { TaskUniqueBuffer = __user_perthread_libspace(); // This task the currently running task, which by definition needs to be the currently running task..., then returns a pointer that is unique for that task. The API does not change .... }
That being said, I want to re-iterate that I am not suggesting using this method at all. I thought you were looking for something like this. You had said....
"I am writing a lib which will cache some data in a buffer. That lib can be called from multiple tasks at the same time, so I want to keep separate buffers for each task.
and that is exactly what this does.
My interest was to provide knowledge on how some things worked. You had 2 questions about TID's so I answered them. I was not making any suggestions for how you use that knowledge. I pointed out that Keil used something similar to what you were suggesting (I was really not suggesting this) to make the C runtime library thread safe. Since it only required 1 variable and 1 function and no change to the API. My guess is that I would not be choosing to implement it this way, but that does not mean that in your specific situation this is not appropriate.
What Keil is doing, is quite similar to how thread local storage is implemented - which was the reason I did mention this concept earlier.
And this is because thread local storage tries to solve the similar problem that Keil wants to solve when they make their CRTL thread-safe.
The other common route to make library functions thread-safe is functions like gmtime_r(), gethostbyname_r() etc where a specific thread-safe variant of standard functions takes a pointer to a thread-local structure. Which obviously doesn't work for malloc() and all other standard C functions where you can't break the API.