Changeset e4ad14cc in rtems for cpukit


Ignore:
Timestamp:
Feb 12, 2019, 11:19:38 AM (4 months ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
3d65f45
Parents:
3ecb207
git-author:
Sebastian Huber <sebastian.huber@…> (02/12/19 11:19:38)
git-committer:
Sebastian Huber <sebastian.huber@…> (02/18/19 06:25:58)
Message:

score: Avoid some deadlocks in _Once()

Recursive usage of the same pthread_once_t results now in a deadlock.
Previously, an error of EINVAL was returned. This usage scenario is
invalid according to the POSIX pthread_once() specification.

Close #3334.

Location:
cpukit
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • cpukit/include/rtems/score/onceimpl.h

    r3ecb207 re4ad14cc  
    88
    99/*
    10  * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
     10 * Copyright (c) 2014, 2019 embedded brains GmbH.  All rights reserved.
    1111 *
    1212 *  embedded brains GmbH
     
    2424#define _RTEMS_ONCE_H
    2525
     26#include <rtems/score/thread.h>
     27
    2628#ifdef __cplusplus
    2729extern "C" {
     
    3840 */
    3941
    40 int _Once( unsigned char *once_state, void (*init_routine)(void) );
     42int _Once( unsigned char *once_state, void ( *init_routine )( void ) );
    4143
    42 void _Once_Lock( void );
     44Thread_Life_state _Once_Lock( void );
    4345
    44 void _Once_Unlock( void );
     46void _Once_Unlock( Thread_Life_state thread_life_state );
    4547
    4648/** @} */
  • cpukit/rtems/src/timerserver.c

    r3ecb207 re4ad14cc  
    229229{
    230230  rtems_status_code status;
    231 
    232   _Once_Lock();
     231  Thread_Life_state thread_life_state;
     232
     233  thread_life_state = _Once_Lock();
    233234  status = _Timer_server_Initiate( priority, stack_size, attribute_set );
    234   _Once_Unlock();
     235  _Once_Unlock( thread_life_state );
    235236
    236237  return status;
  • cpukit/score/src/once.c

    r3ecb207 re4ad14cc  
    11/*
    2  *  COPYRIGHT (c) 1989-1999.
    3  *  On-Line Applications Research Corporation (OAR).
     2 * SPDX-License-Identifier: BSD-2-Clause
    43 *
    5  *  The license and distribution terms for this file may be
    6  *  found in the file LICENSE in this distribution or at
    7  *  http://www.rtems.org/license/LICENSE.
     4 * Copyright (C) 2019 embedded brains GmbH
     5 * Copyright (C) 2019 Sebastian Huber
     6 *
     7 * Redistribution and use in source and binary forms, with or without
     8 * modification, are permitted provided that the following conditions
     9 * are met:
     10 * 1. Redistributions of source code must retain the above copyright
     11 *    notice, this list of conditions and the following disclaimer.
     12 * 2. Redistributions in binary form must reproduce the above copyright
     13 *    notice, this list of conditions and the following disclaimer in the
     14 *    documentation and/or other materials provided with the distribution.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26 * POSSIBILITY OF SUCH DAMAGE.
    827 */
    928
    1029#ifdef HAVE_CONFIG_H
    11   #include "config.h"
     30#include "config.h"
    1231#endif
    1332
    1433#include <rtems/score/onceimpl.h>
    15 #include <rtems/score/apimutex.h>
     34#include <rtems/score/threadimpl.h>
     35#include <rtems/thread.h>
    1636
    17 #include <errno.h>
     37#define ONCE_STATE_INIT 0
    1838
    19 #define ONCE_STATE_NOT_RUN  0
    20 #define ONCE_STATE_RUNNING  1
     39#define ONCE_STATE_RUNNING 1
     40
    2141#define ONCE_STATE_COMPLETE 2
     42
     43typedef struct {
     44  rtems_mutex              Mutex;
     45  rtems_condition_variable State;
     46} Once_Control;
     47
     48static Once_Control _Once_Information = {
     49  .Mutex = RTEMS_MUTEX_INITIALIZER( "_Once" ),
     50  .State = RTEMS_CONDITION_VARIABLE_INITIALIZER( "_Once" )
     51};
    2252
    2353int _Once( unsigned char *once_state, void ( *init_routine )( void ) )
    2454{
    25   int eno = 0;
     55  _Atomic_Fence( ATOMIC_ORDER_ACQUIRE );
    2656
    27   if ( *once_state != ONCE_STATE_COMPLETE ) {
    28     _Once_Lock();
     57  if ( RTEMS_PREDICT_FALSE( *once_state != ONCE_STATE_COMPLETE ) ) {
     58    Thread_Life_state thread_life_state;
    2959
    30     /*
    31      * Getting to here means the once_control is locked so we have:
    32      *  1. The init has not run and the state is ONCE_STATE_NOT_RUN.
    33      *  2. The init has finished and the state is ONCE_STATE_COMPLETE (already
    34      *     caught by the previous if).
    35      *  3. The init is being run by this thread and the state
    36      *     ONCE_STATE_RUNNING so we are nesting. This is an error.
    37      */
     60    thread_life_state = _Once_Lock();
    3861
    39     switch ( *once_state ) {
    40       case ONCE_STATE_NOT_RUN:
    41         *once_state = ONCE_STATE_RUNNING;
    42         ( *init_routine )();
    43         *once_state = ONCE_STATE_COMPLETE;
    44         break;
    45       case ONCE_STATE_RUNNING:
    46         eno = EINVAL;
    47         break;
    48       default:
    49         break;
     62    if ( *once_state == ONCE_STATE_INIT ) {
     63      *once_state = ONCE_STATE_RUNNING;
     64      _Once_Unlock( THREAD_LIFE_PROTECTED );
     65      ( *init_routine )();
     66      _Once_Lock();
     67      _Atomic_Fence( ATOMIC_ORDER_RELEASE );
     68      *once_state = ONCE_STATE_COMPLETE;
     69      rtems_condition_variable_broadcast( &_Once_Information.State );
     70    } else {
     71      while ( *once_state != ONCE_STATE_COMPLETE ) {
     72        rtems_condition_variable_wait(
     73          &_Once_Information.State,
     74          &_Once_Information.Mutex
     75        );
     76      }
    5077    }
    5178
    52     _Once_Unlock();
     79    _Once_Unlock( thread_life_state );
    5380  }
    5481
    55   return eno;
     82  return 0;
    5683}
    5784
    58 static API_Mutex_Control _Once_Mutex = API_MUTEX_INITIALIZER( "_Once" );
     85Thread_Life_state _Once_Lock( void )
     86{
     87  Thread_Life_state thread_life_state;
    5988
    60 void _Once_Lock( void )
    61 {
    62   _API_Mutex_Lock( &_Once_Mutex );
     89  thread_life_state = _Thread_Set_life_protection( THREAD_LIFE_PROTECTED );
     90  rtems_mutex_lock( &_Once_Information.Mutex );
     91
     92  return thread_life_state;
    6393}
    6494
    65 void _Once_Unlock( void )
     95void _Once_Unlock( Thread_Life_state thread_life_state )
    6696{
    67   _API_Mutex_Unlock( &_Once_Mutex );
     97  rtems_mutex_unlock( &_Once_Information.Mutex );
     98  _Thread_Set_life_protection( thread_life_state );
    6899}
Note: See TracChangeset for help on using the changeset viewer.