source: rtems/cpukit/rtems/src/sem.c @ 5250ff39

4.104.114.84.95
Last change on this file since 5250ff39 was 5250ff39, checked in by Joel Sherrill <joel.sherrill@…>, on 08/23/95 at 21:06:31

Moved _Thread_Information -> _RTEMS_tasks_Information.

Added a table of object information control blocks.

Modified _Thread_Get so it looks up a thread regardless of which
thread management "entity" (manager, internal, etc) actually "owns" it.

  • Property mode set to 100644
File size: 13.1 KB
Line 
1/*
2 *  Semaphore Manager
3 *
4 *  DESCRIPTION:
5 *
6 *  This package is the implementation of the Semaphore Manager.
7 *  This manager utilizes standard Dijkstra counting semaphores to provide
8 *  synchronization and mutual exclusion capabilities.
9 *
10 *  Directives provided are:
11 *
12 *     + create a semaphore
13 *     + get an ID of a semaphore
14 *     + delete a semaphore
15 *     + acquire a semaphore
16 *     + release a semaphore
17 *
18 *  COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
19 *  On-Line Applications Research Corporation (OAR).
20 *  All rights assigned to U.S. Government, 1994.
21 *
22 *  This material may be reproduced by or for the U.S. Government pursuant
23 *  to the copyright license under the clause at DFARS 252.227-7013.  This
24 *  notice must appear in all copies of this file and its derivatives.
25 *
26 *  $Id$
27 */
28
29#include <rtems/system.h>
30#include <rtems/support.h>
31#include <rtems/attr.h>
32#include <rtems/config.h>
33#include <rtems/isr.h>
34#include <rtems/object.h>
35#include <rtems/options.h>
36#include <rtems/sem.h>
37#include <rtems/states.h>
38#include <rtems/thread.h>
39#include <rtems/threadq.h>
40#include <rtems/mpci.h>
41
42/*PAGE
43 *
44 *  _Semaphore_Manager_initialization
45 *
46 *  This routine initializes all semaphore manager related data structures.
47 *
48 *  Input parameters:
49 *    maximum_semaphores - maximum configured semaphores
50 *
51 *  Output parameters:  NONE
52 */
53
54void _Semaphore_Manager_initialization(
55  unsigned32 maximum_semaphores
56)
57{
58  _Objects_Initialize_information(
59    &_Semaphore_Information,
60    OBJECTS_RTEMS_SEMAPHORES,
61    TRUE,
62    maximum_semaphores,
63    sizeof( Semaphore_Control ),
64    FALSE,
65    RTEMS_MAXIMUM_NAME_LENGTH,
66    FALSE
67  );
68}
69
70/*PAGE
71 *
72 *  rtems_semaphore_create
73 *
74 *  This directive creates a semaphore and sets the initial value based
75 *  on the given count.  A semaphore id is returned.
76 *
77 *  Input parameters:
78 *    name          - user defined semaphore name
79 *    count         - initial count of semaphore
80 *    attribute_set - semaphore attributes
81 *    id            - pointer to semaphore id
82 *
83 *  Output parameters:
84 *    id       - semaphore id
85 *    RTEMS_SUCCESSFUL - if successful
86 *    error code - if unsuccessful
87 */
88
89rtems_status_code rtems_semaphore_create(
90  rtems_name          name,
91  unsigned32          count,
92  rtems_attribute  attribute_set,
93  Objects_Id         *id
94)
95{
96  register Semaphore_Control *the_semaphore;
97
98  if ( !rtems_is_name_valid( name ) )
99    return ( RTEMS_INVALID_NAME );
100
101  if ( _Attributes_Is_global( attribute_set ) ) {
102
103    if ( !_Configuration_Is_multiprocessing() )
104      return( RTEMS_MP_NOT_CONFIGURED );
105
106    if ( _Attributes_Is_inherit_priority( attribute_set ) )
107      return( RTEMS_NOT_DEFINED );
108
109  } else if ( _Attributes_Is_inherit_priority( attribute_set ) ) {
110
111    if ( ! ( _Attributes_Is_binary_semaphore( attribute_set ) &&
112             _Attributes_Is_priority( attribute_set ) ) )
113      return( RTEMS_NOT_DEFINED );
114
115  }
116
117  if ( _Attributes_Is_binary_semaphore( attribute_set ) && ( count > 1 ) )
118    return( RTEMS_INVALID_NUMBER );
119
120  _Thread_Disable_dispatch();             /* prevents deletion */
121
122  the_semaphore = _Semaphore_Allocate();
123
124  if ( !the_semaphore ) {
125    _Thread_Enable_dispatch();
126    return( RTEMS_TOO_MANY );
127  }
128
129  if ( _Attributes_Is_global( attribute_set ) &&
130       !( _Objects_MP_Open( &_Semaphore_Information, name,
131                            the_semaphore->Object.id, FALSE ) ) ) {
132    _Semaphore_Free( the_semaphore );
133    _Thread_Enable_dispatch();
134    return( RTEMS_TOO_MANY );
135  }
136
137  the_semaphore->attribute_set = attribute_set;
138  the_semaphore->count         = count;
139
140  if ( _Attributes_Is_binary_semaphore( attribute_set ) && count == 0 ) {
141    the_semaphore->nest_count = 1;
142    the_semaphore->holder     = _Thread_Executing;
143    the_semaphore->holder_id  = _Thread_Executing->Object.id;
144    _Thread_Executing->resource_count++;
145  } else {
146    the_semaphore->nest_count = 0;
147    the_semaphore->holder     = NULL;
148    the_semaphore->holder_id  = 0;
149  }
150
151  _Thread_queue_Initialize( &the_semaphore->Wait_queue,
152                            attribute_set, STATES_WAITING_FOR_SEMAPHORE );
153
154  _Objects_Open( &_Semaphore_Information, &the_semaphore->Object, &name );
155
156  *id = the_semaphore->Object.id;
157
158  if ( _Attributes_Is_global( attribute_set ) )
159    _Semaphore_MP_Send_process_packet(
160      SEMAPHORE_MP_ANNOUNCE_CREATE,
161      the_semaphore->Object.id,
162      name,
163      0                          /* Not used */
164    );
165  _Thread_Enable_dispatch();
166  return( RTEMS_SUCCESSFUL );
167}
168
169/*PAGE
170 *
171 *  rtems_semaphore_ident
172 *
173 *  This directive returns the system ID associated with
174 *  the semaphore name.
175 *
176 *  Input parameters:
177 *    name - user defined semaphore name
178 *    node - node(s) to be searched
179 *    id   - pointer to semaphore id
180 *
181 *  Output parameters:
182 *    *id      - semaphore id
183 *    RTEMS_SUCCESSFUL - if successful
184 *    error code - if unsuccessful
185 */
186
187rtems_status_code rtems_semaphore_ident(
188  rtems_name    name,
189  unsigned32    node,
190  Objects_Id   *id
191)
192{
193  return( _Objects_Name_to_id( &_Semaphore_Information, &name, node, id ) );
194}
195
196/*PAGE
197 *
198 *  rtems_semaphore_delete
199 *
200 *  This directive allows a thread to delete a semaphore specified by
201 *  the semaphore id.  The semaphore is freed back to the inactive
202 *  semaphore chain.
203 *
204 *  Input parameters:
205 *    id - semaphore id
206 *
207 *  Output parameters:
208 *    RTEMS_SUCCESSFUL - if successful
209 *    error code        - if unsuccessful
210 */
211
212rtems_status_code rtems_semaphore_delete(
213  Objects_Id id
214)
215{
216  register Semaphore_Control *the_semaphore;
217  Objects_Locations           location;
218
219  the_semaphore = _Semaphore_Get( id, &location );
220  switch ( location ) {
221    case OBJECTS_ERROR:
222      return( RTEMS_INVALID_ID );
223    case OBJECTS_REMOTE:
224      _Thread_Dispatch();
225      return( RTEMS_ILLEGAL_ON_REMOTE_OBJECT );
226    case OBJECTS_LOCAL:
227      if ( _Attributes_Is_binary_semaphore( the_semaphore->attribute_set) &&
228                       ( the_semaphore->count == 0 ) ) {
229        _Thread_Enable_dispatch();
230        return( RTEMS_RESOURCE_IN_USE );
231      }
232
233      _Objects_Close( &_Semaphore_Information, &the_semaphore->Object );
234
235      _Thread_queue_Flush(
236        &the_semaphore->Wait_queue,
237        _Semaphore_MP_Send_object_was_deleted
238      );
239
240      _Semaphore_Free( the_semaphore );
241
242      if ( _Attributes_Is_global( the_semaphore->attribute_set ) ) {
243
244        _Objects_MP_Close( &_Semaphore_Information, the_semaphore->Object.id );
245
246        _Semaphore_MP_Send_process_packet(
247          SEMAPHORE_MP_ANNOUNCE_DELETE,
248          the_semaphore->Object.id,
249          0,                         /* Not used */
250          0                          /* Not used */
251        );
252      }
253      _Thread_Enable_dispatch();
254      return( RTEMS_SUCCESSFUL );
255  }
256
257  return( RTEMS_INTERNAL_ERROR );   /* unreached - only to remove warnings */
258}
259
260/*PAGE
261 *
262 *  rtems_semaphore_obtain
263 *
264 *  This directive allows a thread to acquire a semaphore.
265 *
266 *  Input parameters:
267 *    id         - semaphore id
268 *    option_set - wait option
269 *    timeout    - number of ticks to wait (0 means wait forever)
270 *
271 *  Output parameters:
272 *    RTEMS_SUCCESSFUL - if successful
273 *    error code        - if unsuccessful
274 */
275
276rtems_status_code rtems_semaphore_obtain(
277  Objects_Id        id,
278  unsigned32        option_set,
279  rtems_interval timeout
280)
281{
282  register Semaphore_Control *the_semaphore;
283  Objects_Locations           location;
284
285  the_semaphore = _Semaphore_Get( id, &location );
286  switch ( location ) {
287    case OBJECTS_ERROR:
288      return( RTEMS_INVALID_ID );
289    case OBJECTS_REMOTE:
290      return _Semaphore_MP_Send_request_packet(
291          SEMAPHORE_MP_OBTAIN_REQUEST,
292          id,
293          option_set,
294          timeout
295      );
296    case OBJECTS_LOCAL:
297      if ( !_Semaphore_Seize( the_semaphore, option_set ) ) {
298        if ( _Attributes_Is_inherit_priority( the_semaphore->attribute_set ) &&
299             the_semaphore->holder->current_priority >
300               _Thread_Executing->current_priority ) {
301            _Thread_Change_priority(
302              the_semaphore->holder, _Thread_Executing->current_priority );
303         }
304        _Thread_queue_Enqueue( &the_semaphore->Wait_queue, timeout );
305      }
306      _Thread_Enable_dispatch();
307      return( _Thread_Executing->Wait.return_code );
308  }
309
310  return( RTEMS_INTERNAL_ERROR );   /* unreached - only to remove warnings */
311}
312
313/*PAGE
314 *
315 *  rtems_semaphore_release
316 *
317 *  This directive allows a thread to release a semaphore.
318 *
319 *  Input parameters:
320 *    id - semaphore id
321 *
322 *  Output parameters:
323 *    RTEMS_SUCCESSFUL - if successful
324 *    error code        - if unsuccessful
325 */
326
327rtems_status_code rtems_semaphore_release(
328  Objects_Id id
329)
330{
331  register Semaphore_Control *the_semaphore;
332  Objects_Locations           location;
333  Thread_Control             *the_thread;
334
335  the_semaphore = _Semaphore_Get( id, &location );
336  switch ( location ) {
337    case OBJECTS_ERROR:
338      return( RTEMS_INVALID_ID );
339    case OBJECTS_REMOTE:
340      return(
341        _Semaphore_MP_Send_request_packet(
342          SEMAPHORE_MP_RELEASE_REQUEST,
343          id,
344          0,                               /* Not used */
345          MPCI_DEFAULT_TIMEOUT
346        )
347      );
348    case OBJECTS_LOCAL:
349      if ( _Attributes_Is_binary_semaphore( the_semaphore->attribute_set)) {
350
351        if ( !_Objects_Are_ids_equal(
352               _Thread_Executing->Object.id, the_semaphore->holder_id ) ) {
353          _Thread_Enable_dispatch();
354          return( RTEMS_NOT_OWNER_OF_RESOURCE );
355        }
356
357        the_semaphore->nest_count--;
358
359        if ( the_semaphore->nest_count != 0 ) {
360          _Thread_Enable_dispatch();
361          return( RTEMS_SUCCESSFUL );
362        }
363
364        _Thread_Executing->resource_count--;
365        the_semaphore->holder    = NULL;
366        the_semaphore->holder_id = 0;
367
368        /*
369         *  Whether or not someone is waiting for the semaphore, an
370         *  inherited priority must be lowered if this is the last
371         *  semaphore (i.e. resource) this task has.
372         */
373
374        if ( _Attributes_Is_inherit_priority(the_semaphore->attribute_set) &&
375             _Thread_Executing->resource_count == 0 &&
376             _Thread_Executing->real_priority !=
377                _Thread_Executing->current_priority ) {
378           _Thread_Change_priority(
379              _Thread_Executing, _Thread_Executing->real_priority );
380        }
381
382      }
383
384      if ( (the_thread = _Thread_queue_Dequeue(&the_semaphore->Wait_queue)) ) {
385
386        if ( !_Objects_Is_local_id( the_thread->Object.id ) ) {
387          the_thread->receive_packet->return_code = RTEMS_SUCCESSFUL;
388
389          if ( _Attributes_Is_binary_semaphore(the_semaphore->attribute_set) ) {
390            the_semaphore->holder    = NULL;
391            the_semaphore->holder_id = the_thread->Object.id;
392            the_semaphore->nest_count = 1;
393          }
394
395          _Semaphore_MP_Send_response_packet(
396            SEMAPHORE_MP_OBTAIN_RESPONSE,
397            id,
398            the_thread
399          );
400        } else {
401
402          if ( _Attributes_Is_binary_semaphore(the_semaphore->attribute_set) ) {
403            the_semaphore->holder    = the_thread;
404            the_semaphore->holder_id = the_thread->Object.id;
405            the_thread->resource_count++;
406            the_semaphore->nest_count = 1;
407          }
408
409          /*
410           *  No special action for priority inheritance because the_thread
411           *  is guaranteed to be the highest priority thread waiting for
412           *  the semaphore.
413           */
414        }
415      } else
416        the_semaphore->count += 1;
417
418      _Thread_Enable_dispatch();
419      return( RTEMS_SUCCESSFUL );
420  }
421
422  return( RTEMS_INTERNAL_ERROR );   /* unreached - only to remove warnings */
423}
424
425/*PAGE
426 *
427 *  _Semaphore_Seize
428 *
429 *  This routine attempts to allocate a semaphore to the calling thread.
430 *
431 *  Input parameters:
432 *    the_semaphore - pointer to semaphore control block
433 *    option_set    - acquire semaphore options
434 *
435 *  Output parameters:
436 *    TRUE  - if semaphore allocated
437 *    FALSE - if semaphore NOT allocated
438 *
439 *  INTERRUPT LATENCY:
440 *    available
441 *    wait
442 */
443
444boolean _Semaphore_Seize(
445  Semaphore_Control *the_semaphore,
446  rtems_option    option_set
447)
448{
449  Thread_Control *executing;
450  ISR_Level       level;
451
452  executing = _Thread_Executing;
453  executing->Wait.return_code = RTEMS_SUCCESSFUL;
454  _ISR_Disable( level );
455  if ( the_semaphore->count != 0 ) {
456    the_semaphore->count -= 1;
457    if ( _Attributes_Is_binary_semaphore( the_semaphore->attribute_set ) ) {
458      the_semaphore->holder     = executing;
459      the_semaphore->holder_id  = executing->Object.id;
460      the_semaphore->nest_count = 1;
461      executing->resource_count++;
462    }
463    _ISR_Enable( level );
464    return( TRUE );
465  }
466
467  if ( _Options_Is_no_wait( option_set ) ) {
468    _ISR_Enable( level );
469    executing->Wait.return_code = RTEMS_UNSATISFIED;
470    return( TRUE );
471  }
472
473  if ( _Attributes_Is_binary_semaphore( the_semaphore->attribute_set ) ) {
474    if ( _Objects_Are_ids_equal(
475            _Thread_Executing->Object.id, the_semaphore->holder_id ) ) {
476      the_semaphore->nest_count++;
477      _ISR_Enable( level );
478      return( TRUE );
479    }
480  }
481
482  the_semaphore->Wait_queue.sync = TRUE;
483  executing->Wait.queue      = &the_semaphore->Wait_queue;
484  executing->Wait.id         = the_semaphore->Object.id;
485  executing->Wait.option_set = option_set;
486  _ISR_Enable( level );
487  return( FALSE );
488}
Note: See TracBrowser for help on using the repository browser.