This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Are values of OS_TID deterministic?

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

Parents
  • 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.

Reply
  • 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.

Children
  • 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.