source: rtems/cpukit/rtems/src/sem.c @ 9863dbf

4.104.114.84.95
Last change on this file since 9863dbf was 9863dbf, checked in by Joel Sherrill <joel.sherrill@…>, on 08/18/95 at 21:42:58

+ Added object type field to object id.

+ Added name pointer to Object_Control.

+ Modified Object Open and Close to address name field.

+ Removed name as separate element from Thread and Proxy Control.

+ Added parameter "object class" to calls to Initialize Information

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