summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/threadtimeout.c
blob: b6ce2d7362bf58323d2630d5f42dca59107ed716 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
 * @file
 *
 * @brief Thread Wait Timeout
 *
 * @ingroup ScoreThread
 */

/*
 *  COPYRIGHT (c) 1989-2008.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

#if HAVE_CONFIG_H
  #include "config.h"
#endif

#include <rtems/score/threadimpl.h>

static void _Thread_Do_timeout( Thread_Control *the_thread )
{
  the_thread->Wait.return_code = the_thread->Wait.timeout_code;
  _Thread_Lock_restore_default( the_thread );
}

void _Thread_Timeout( Objects_Id id, void *arg )
{
  Thread_Control    *the_thread;
  ISR_lock_Control  *thread_lock;
  ISR_lock_Context   lock_context;
  Thread_Wait_flags  wait_flags;
  Thread_Wait_flags  wait_class;
  Thread_Wait_flags  intend_to_block;
  Thread_Wait_flags  blocked;
  bool               success;
  bool               unblock;

  the_thread = arg;
  thread_lock = _Thread_Lock_acquire( the_thread, &lock_context );

  wait_flags = _Thread_Wait_flags_get( the_thread );
  wait_class = wait_flags & THREAD_WAIT_CLASS_MASK;
  intend_to_block = wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK;
  blocked = wait_class | THREAD_WAIT_STATE_BLOCKED;
  success = _Thread_Wait_flags_try_change_critical(
    the_thread,
    intend_to_block,
    wait_class | THREAD_WAIT_STATE_READY_AGAIN
  );

  if ( success ) {
    _Thread_Do_timeout( the_thread );
    unblock = false;
  } else if ( _Thread_Wait_flags_get( the_thread ) == blocked ) {
    _Thread_Wait_flags_set(
      the_thread,
      wait_class | THREAD_WAIT_STATE_READY_AGAIN
    );
    _Thread_Do_timeout( the_thread );
    unblock = true;
  } else {
    unblock = false;
  }

  _Thread_Lock_release( thread_lock, &lock_context );

  if ( unblock ) {
    _Thread_Unblock( the_thread );
  }
}