source: rtems/cpukit/rtems/src/sem.c @ 3235ad9

4.104.114.84.95
Last change on this file since 3235ad9 was 3235ad9, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 23, 1995 at 7:30:23 PM

Support for variable length names added to Object Handler. This supports
both fixed length "raw" names and strings from the API's point of view.

Both inline and macro implementations were tested.

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