source: rtems/cpukit/score/src/futex.c @ c3105894

5
Last change on this file since c3105894 was c3105894, checked in by Sebastian Huber <sebastian.huber@…>, on 10/19/17 at 11:47:57

score: Move thread queue timeout handling

Update #3117.
Update #3182.

  • Property mode set to 100644
File size: 3.9 KB
Line 
1/*
2 * Copyright (c) 2015, 2016 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#if HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <sys/lock.h>
20#include <errno.h>
21
22#include <rtems/score/atomic.h>
23#include <rtems/score/chainimpl.h>
24#include <rtems/score/threadimpl.h>
25#include <rtems/score/threadqimpl.h>
26
27#define FUTEX_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
28
29typedef struct {
30  Thread_queue_Syslock_queue Queue;
31} Futex_Control;
32
33RTEMS_STATIC_ASSERT(
34  offsetof( Futex_Control, Queue )
35    == offsetof( struct _Futex_Control, _Queue ),
36  FUTEX_CONTROL_QUEUE
37);
38
39RTEMS_STATIC_ASSERT(
40  sizeof( Futex_Control ) == sizeof( struct _Futex_Control ),
41  FUTEX_CONTROL_SIZE
42);
43
44static Futex_Control *_Futex_Get( struct _Futex_Control *_futex )
45{
46  return (Futex_Control *) _futex;
47}
48
49static Thread_Control *_Futex_Queue_acquire_critical(
50  Futex_Control        *futex,
51  Thread_queue_Context *queue_context
52)
53{
54  Thread_Control *executing;
55
56  executing = _Thread_Executing;
57  _Thread_queue_Queue_acquire_critical(
58    &futex->Queue.Queue,
59    &executing->Potpourri_stats,
60    &queue_context->Lock_context.Lock_context
61  );
62
63  return executing;
64}
65
66static void _Futex_Queue_release(
67  Futex_Control        *futex,
68  ISR_Level             level,
69  Thread_queue_Context *queue_context
70)
71{
72  _Thread_queue_Queue_release_critical(
73    &futex->Queue.Queue,
74    &queue_context->Lock_context.Lock_context
75  );
76  _ISR_Local_enable( level );
77}
78
79int _Futex_Wait( struct _Futex_Control *_futex, int *uaddr, int val )
80{
81  Futex_Control        *futex;
82  ISR_Level             level;
83  Thread_queue_Context  queue_context;
84  Thread_Control       *executing;
85  int                   eno;
86
87  futex = _Futex_Get( _futex );
88  _Thread_queue_Context_initialize( &queue_context );
89  _Thread_queue_Context_ISR_disable( &queue_context, level );
90  executing = _Futex_Queue_acquire_critical( futex, &queue_context );
91
92  if ( *uaddr == val ) {
93    _Thread_queue_Context_set_thread_state(
94      &queue_context,
95      STATES_WAITING_FOR_FUTEX
96    );
97    _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
98    _Thread_queue_Context_set_ISR_level( &queue_context, level );
99    _Thread_queue_Enqueue(
100      &futex->Queue.Queue,
101      FUTEX_TQ_OPERATIONS,
102      executing,
103      &queue_context
104    );
105    eno = 0;
106  } else {
107    _Futex_Queue_release( futex, level, &queue_context );
108    eno = EWOULDBLOCK;
109  }
110
111  return eno;
112}
113
114typedef struct {
115  Thread_queue_Context Base;
116  int                  count;
117} Futex_Context;
118
119static Thread_Control *_Futex_Flush_filter(
120  Thread_Control       *the_thread,
121  Thread_queue_Queue   *queue,
122  Thread_queue_Context *queue_context
123)
124{
125  Futex_Context *context;
126
127  context = (Futex_Context *) queue_context;
128
129  if ( context->count <= 0 ) {
130    return NULL;
131  }
132
133  --context->count;
134
135  return the_thread;
136}
137
138int _Futex_Wake( struct _Futex_Control *_futex, int count )
139{
140  Futex_Control *futex;
141  ISR_Level      level;
142  Futex_Context  context;
143
144  futex = _Futex_Get( _futex );
145  _Thread_queue_Context_initialize( &context.Base );
146  _Thread_queue_Context_ISR_disable( &context.Base, level );
147  _Futex_Queue_acquire_critical( futex, &context.Base );
148
149  /*
150   * For some synchronization objects like barriers the _Futex_Wake() must be
151   * called in the fast path.  Normally there are no threads on the queue, so
152   * check this condition early.
153   */
154  if ( __predict_true( _Thread_queue_Is_empty( &futex->Queue.Queue ) ) ) {
155    _Futex_Queue_release( futex, level, &context.Base );
156    return 0;
157  }
158
159  context.count = count;
160  _Thread_queue_Context_set_ISR_level( &context.Base, level );
161  return (int) _Thread_queue_Flush_critical(
162    &futex->Queue.Queue,
163    FUTEX_TQ_OPERATIONS,
164    _Futex_Flush_filter,
165    &context.Base
166  );
167}
Note: See TracBrowser for help on using the repository browser.