Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMSIS RTOSv2 API: thread interruption/cancellation #68

Closed
ilg-ul opened this issue Jul 8, 2016 · 6 comments
Closed

CMSIS RTOSv2 API: thread interruption/cancellation #68

ilg-ul opened this issue Jul 8, 2016 · 6 comments

Comments

@ilg-ul
Copy link
Contributor

ilg-ul commented Jul 8, 2016

I did not yet see the full documentation pages for these functions, so my understanding of these functions might not be accurate, but I wanted to share my experience with CMSIS++.

As already mentioned in #67, the two mandatory scheduler functions are suspend() and resume(), which apparently map properly to osThreadSuspend() and osThreadResume().

As for the osThreadAbortWait(), I'm not sure what it was intended for. If it was intended to resume a thread suspended while waiting for an event, osThreadResume() should do the job.

If it was intended to provide a method to interrupt a running thread, then, based on the experience with implementing the CMSIS++ portable synchronisation objects, things are a bit more complicated.

The API used by CMSIS++ for this purpose involves two functions:

      bool
      interrupted (void);

      bool
      interrupt (bool interrupt = true);

Each thread has a boolean flag to store the interrupted state. The first function returns this flag. The second function sets/resets this flag.

In addition, the interrupt(bool) function will also resume the thread, if the flag is true.

Now the whole trick is how to use this flag to break some waits.

For example, here is the semaphore::timed_wait() implementation:

    result_t
    semaphore::timed_wait (clock::duration_t timeout)
    {
      os_assert_err(!interrupts::in_handler_mode (), EPERM);

#if defined(OS_TRACE_RTOS_SEMAPHORE)
      trace::printf ("%s(%u) @%p %s\n", __func__,
                     static_cast<unsigned int> (timeout), this, name ());
#endif

#if defined(OS_USE_RTOS_PORT_SEMAPHORE)

      return port::semaphore::timed_wait (this, timeout);

#else

      // Extra test before entering the loop, with its inherent weight.
      // Trade size for speed.
        {
          interrupts::critical_section ics; // ----- Critical section -----

          if (_try_wait ())
            {
              return result::ok;
            }
        }

      thread& crt_thread = this_thread::thread ();

      // Prepare a list node pointing to the current thread.
      // Do not worry for being on stack, it is temporarily linked to the
      // list and guaranteed to be removed before this function returns.
      waiting_thread_node node
        { crt_thread };

      clock_timestamps_list& clock_list = clock_->steady_list ();
      clock::timestamp_t timeout_timestamp = clock_->steady_now () + timeout;

      // Prepare a timeout node pointing to the current thread.
      timeout_thread_node timeout_node
        { timeout_timestamp, crt_thread };

      for (;;)
        {
            {
              interrupts::critical_section ics; // ----- Critical section -----

              if (_try_wait ())
                {
                  return result::ok;
                }

              // Add this thread to the semaphore waiting list,
              // and the clock timeout list.
              scheduler::_link_node (list_, node, clock_list, timeout_node);
              // state::waiting set in above link().
            }

          port::scheduler::reschedule ();

          // Remove the thread from the semaphore waiting list,
          // if not already removed by post() and from the clock
          // timeout list, if not already removed by the timer.
          scheduler::_unlink_node (node, timeout_node);

          if (crt_thread.interrupted ())
            {
              return EINTR;
            }

          if (clock_->steady_now () >= timeout_timestamp)
            {
              return ETIMEDOUT;
            }
        }

      /* NOTREACHED */
      return ENOTRECOVERABLE;

#endif
    }

As it can be seen, the interrupted() condition is checked immediately after the thread is resumed, and, if detected, the standard POSIX EINTR error is returned. This pattern should is applied to all waiting loops.

Suggestion:

  • clarify what osThreadAbortWait() is supposed to do; if it is supposed to handle interruptions, consider the more elaborate mechanism used by CMSIS++
@ilg-ul
Copy link
Contributor Author

ilg-ul commented Sep 15, 2016

since the new documentation did not mention thread interruption for osThreadAbortWait(), see #83 for an updated suggestion.

@RobertRostohar
Copy link
Collaborator

Resolved as suggested in #83.

@ilg-ul
Copy link
Contributor Author

ilg-ul commented Oct 12, 2016

since osThreadAbortWait() is gone, I renamed the issue to reflect the original concern, a mechanism to inform the thread that it was interrupted.

@ilg-ul ilg-ul changed the title CMSIS RTOSv2 API: osThreadAbortWait() vs osThreadResume() CMSIS RTOSv2 API: thread interruption/cancellation Oct 12, 2016
@JonatanAntoni
Copy link
Member

Is this problem resolved in the meantime? I.e. in favor of #69? Or do we need to discuss another aspect of thread handling here?

@ilg-ul
Copy link
Contributor Author

ilg-ul commented Feb 27, 2017

I'm not sure, both #69 and #83 deal with slightly different issues.

A quick look at the values returned by some blocking functions did not reveal an equivalent of POSIX EINTR, i.e. a blocking function was forced to terminate.

A waiting thread can be resumed with osWaitResume() at any time, but usually this makes the thread just check the waiting condition and possibly sleep again.

To interrupt a thread, a separate flag should be set beforeosWaitResume() and checked by the resumed thread, if the condition is still false.

For a uniform and convenient usage, in CMSIS++ I preferred to add this flag to the thread together with the functions to set/reset/check it.

@JonatanAntoni
Copy link
Member

@ilg-ul I am a bit confused. You have written about osWaitResume() which is not CMSIS-RTOS2-API. Or do you still talk about osThreadResume()? Originally you stated osThreadAbortWait() as well, which is not CMSIS-RTOS2-API as today. Something like POSIX signals leading to blocking function return EINTR without having fulfilled their duty are not intended by the CMSIS-RTOS2-API at the moment.

May I ask you to clarify or update this issue referring to the latest RTOS2-API, please? Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants