source: rtems/c/src/exec/rtems/src/sem.c @ 4ca27cf

4.104.114.84.95
Last change on this file since 4ca27cf was ac7d5ef0, checked in by Joel Sherrill <joel.sherrill@…>, on 05/11/95 at 17:39:37

Initial revision

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