Hello,

we are trying to describe the rtems formatting style using clang-format (
http://clang.llvm.org/docs/ClangFormatStyleOptions.html).
To see whether it can be done, we used ratemonperiod.c as an example and
tried to set up a .clang-format file to describe the formatting.
In the mail added the .clang configuration file and a
ratemonperiodWKCustom_Commented.c, which is ratemonperiod.c with the
configuration in .clang-format applied.

With the .clang-format file in the folder with the source files, it can be
tried out with:
clang-format -style=file original_source.c > formatted_source.c

There are several problems in ratemonperiodWKCustom_Commented.c using
clang-format:

1. In line 30-32, we can see that the "*" of the pointers are not aligned
to the right. This is not supported yet it clang-format (see
https://stackoverflow.com/questions/38392889/clang-format-align-asterisk-of-pointer-declaration-with-variable-name
).

2. In line 32, the ")" at the end of the parameter list needs to be in a
new row, but this doesn't seem to be supported in clang-format.

4. In line 44: If the function call is split into multiple rows, the ");"
should always be in a new row.

5. Also in line 44, when a function call is split into multiple rows. The
parameters can all be in separate rows, but clang-format always puts all
the parameters in one row when they fit.

6. In line 80, clang-format does not stick to the column limit of 80. The
line is 81 long. I have tried to configure a strict 80 column rule with the
penalties, but there are still lines with 81 characters.

7. In line 127, I can't turn off the break after the function return type
in this case.

8. In line 127, the parameter is not in a new line, but in rtems we would
need every parameter of a function definition to always be in seperate
line. Line 182, 279 have the same problem.

8. Lines 323, 330, 335, 348: It should be possible to specify that the
functions arguments can be in seperate rows.

We have also asked the clang community how much effort it would take to
implement these points.

Best,
Mikail

Attachment: .clang-format
Description: Binary data

/**
 *  @file
 *
 *  @brief Rate Monotonic Support
 *  @ingroup ClassicRateMon
 */

/*
 *  COPYRIGHT (c) 1989-2010.
 *  On-Line Applications Research Corporation (OAR).
 *  Copyright (c) 2016 embedded brains GmbH.
 *  COPYRIGHT (c) 2016 Kuan-Hsun Chen.
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/rtems/ratemonimpl.h>
#include <rtems/score/schedulerimpl.h>
#include <rtems/score/todimpl.h>

bool _Rate_monotonic_Get_status(
  const Rate_monotonic_Control *the_period,
  Timestamp_Control            *wall_since_last_period,
  Timestamp_Control            *cpu_since_last_period
)
{
  Timestamp_Control        uptime;
  Thread_Control          *owning_thread = the_period->owner;
  Timestamp_Control        used;

  /*
   *  Determine elapsed wall time since period initiated.
   */
  _TOD_Get_uptime( &uptime );
  _Timestamp_Subtract(
    &the_period->time_period_initiated, &uptime, wall_since_last_period
  );

  /*
   *  Determine cpu usage since period initiated.
   */
  _Thread_Get_CPU_time_used( owning_thread, &used );

  /*
   *  The cpu usage info was reset while executing.  Can't
   *  determine a status.
   */
  if ( _Timestamp_Less_than( &used, &the_period->cpu_usage_period_initiated ) )
    return false;

   /* used = current cpu usage - cpu usage at start of period */
  _Timestamp_Subtract(
    &the_period->cpu_usage_period_initiated,
    &used,
    cpu_since_last_period
  );

  return true;
}

static void _Rate_monotonic_Release_postponed_job(
  Rate_monotonic_Control *the_period,
  Thread_Control         *owner,
  rtems_interval          next_length,
  ISR_lock_Context       *lock_context
)
{
  Per_CPU_Control      *cpu_self;
  Thread_queue_Context  queue_context;

  --the_period->postponed_jobs;
  _Scheduler_Release_job(
    owner,
    &the_period->Priority,
    the_period->latest_deadline,
    &queue_context
  );

  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
  _Rate_monotonic_Release( the_period, lock_context );
  _Thread_Priority_update( &queue_context );
  _Thread_Dispatch_direct( cpu_self );
}

static void _Rate_monotonic_Release_job(
  Rate_monotonic_Control *the_period,
  Thread_Control         *owner,
  rtems_interval          next_length,
  ISR_lock_Context       *lock_context
)
{
  Per_CPU_Control      *cpu_self;
  Thread_queue_Context  queue_context;
  uint64_t              deadline;

  cpu_self = _Thread_Dispatch_disable_critical( lock_context );

  deadline = _Watchdog_Per_CPU_insert_ticks(
    &the_period->Timer,
    cpu_self,
    next_length
  );
  _Scheduler_Release_job(
    owner,
    &the_period->Priority,
    deadline,
    &queue_context
  );

  _Rate_monotonic_Release( the_period, lock_context );
  _Thread_Priority_update( &queue_context );
  _Thread_Dispatch_enable( cpu_self );
}

void _Rate_monotonic_Restart(
  Rate_monotonic_Control *the_period,
  Thread_Control         *owner,
  ISR_lock_Context       *lock_context
)
{
  /*
   *  Set the starting point and the CPU time used for the statistics.
   */
  _TOD_Get_uptime( &the_period->time_period_initiated );
  _Thread_Get_CPU_time_used( owner, &the_period->cpu_usage_period_initiated );

  _Rate_monotonic_Release_job(
    the_period,
    owner,
    the_period->next_length,
    lock_context
  );
}

static void _Rate_monotonic_Update_statistics(
  Rate_monotonic_Control    *the_period
)
{
  Timestamp_Control          executed;
  Timestamp_Control          since_last_period;
  Rate_monotonic_Statistics *stats;
  bool                       valid_status;

  /*
   *  Assume we are only called in states where it is appropriate
   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
   *  and RATE_MONOTONIC_EXPIRED.
   */

  /*
   *  Update the counts.
   */
  stats = &the_period->Statistics;
  stats->count++;

  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
    stats->missed_count++;

  /*
   *  Grab status for time statistics.
   */
  valid_status =
    _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
  if (!valid_status)
    return;

  /*
   *  Update CPU time
   */
  _Timestamp_Add_to( &stats->total_cpu_time, &executed );

  if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
    stats->min_cpu_time = executed;

  if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
    stats->max_cpu_time = executed;

  /*
   *  Update Wall time
   */
  _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );

  if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
    stats->min_wall_time = since_last_period;

  if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
    stats->max_wall_time = since_last_period;
}

static rtems_status_code _Rate_monotonic_Get_status_for_state(
  rtems_rate_monotonic_period_states state
)
{
  switch ( state ) {
    case RATE_MONOTONIC_INACTIVE:
      return RTEMS_NOT_DEFINED;
    case RATE_MONOTONIC_EXPIRED:
      return RTEMS_TIMEOUT;
    default:
      _Assert( state == RATE_MONOTONIC_ACTIVE );
      return RTEMS_SUCCESSFUL;
  }
}

static rtems_status_code _Rate_monotonic_Activate(
  Rate_monotonic_Control *the_period,
  rtems_interval          length,
  Thread_Control         *executing,
  ISR_lock_Context       *lock_context
)
{
  the_period->postponed_jobs = 0;
  the_period->state = RATE_MONOTONIC_ACTIVE;
  the_period->next_length = length;
  _Rate_monotonic_Restart( the_period, executing, lock_context );
  return RTEMS_SUCCESSFUL;
}

static rtems_status_code _Rate_monotonic_Block_while_active(
  Rate_monotonic_Control *the_period,
  rtems_interval          length,
  Thread_Control         *executing,
  ISR_lock_Context       *lock_context
)
{
  Per_CPU_Control *cpu_self;
  bool             success;

  /*
   *  Update statistics from the concluding period.
   */
  _Rate_monotonic_Update_statistics( the_period );

  /*
   *  This tells the _Rate_monotonic_Timeout that this task is
   *  in the process of blocking on the period and that we
   *  may be changing the length of the next period.
   */
  the_period->next_length = length;
  executing->Wait.return_argument = the_period;
  _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK );

  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
  _Rate_monotonic_Release( the_period, lock_context );

  _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );

  success = _Thread_Wait_flags_try_change_acquire(
    executing,
    RATE_MONOTONIC_INTEND_TO_BLOCK,
    RATE_MONOTONIC_BLOCKED
  );
  if ( !success ) {
    _Assert(
      _Thread_Wait_flags_get( executing ) == RATE_MONOTONIC_READY_AGAIN
    );
    _Thread_Unblock( executing );
  }

  _Thread_Dispatch_direct( cpu_self );
  return RTEMS_SUCCESSFUL;
}

/*
 * There are two possible cases: one is that the previous deadline is missed,
 * The other is that the number of postponed jobs is not 0, but the current
 * deadline is still not expired, i.e., state = RATE_MONOTONIC_ACTIVE.
 */
static rtems_status_code _Rate_monotonic_Block_while_expired(
  Rate_monotonic_Control *the_period,
  rtems_interval          length,
  Thread_Control         *executing,
  ISR_lock_Context       *lock_context
)
{
  /*
   * No matter the just finished jobs in time or not,
   * they are actually missing their deadlines already.
   */
  the_period->state = RATE_MONOTONIC_EXPIRED;

  /*
   * Update statistics from the concluding period
   */
  _Rate_monotonic_Update_statistics( the_period );

  the_period->state = RATE_MONOTONIC_ACTIVE;
  the_period->next_length = length;

  _Rate_monotonic_Release_postponed_job(
      the_period,
      executing,
      length,
      lock_context
  );
  return RTEMS_TIMEOUT;
}

rtems_status_code rtems_rate_monotonic_period(
  rtems_id       id,
  rtems_interval length
)
{
  Rate_monotonic_Control            *the_period;
  ISR_lock_Context                   lock_context;
  Thread_Control                    *executing;
  rtems_status_code                  status;
  rtems_rate_monotonic_period_states state;

  the_period = _Rate_monotonic_Get( id, &lock_context );
  if ( the_period == NULL ) {
    return RTEMS_INVALID_ID;
  }

  executing = _Thread_Executing;
  if ( executing != the_period->owner ) {
    _ISR_lock_ISR_enable( &lock_context );
    return RTEMS_NOT_OWNER_OF_RESOURCE;
  }

  _Rate_monotonic_Acquire_critical( the_period, &lock_context );

  state = the_period->state;

  if ( length == RTEMS_PERIOD_STATUS ) {
    status = _Rate_monotonic_Get_status_for_state( state );
    _Rate_monotonic_Release( the_period, &lock_context );
  } else {
    switch ( state ) {
      case RATE_MONOTONIC_ACTIVE:

        if( the_period->postponed_jobs > 0 ){
          /*
           * If the number of postponed jobs is not 0, it means the
           * previous postponed instance is finished without exceeding
           * the current period deadline.
           *
           * Do nothing on the watchdog deadline assignment but release the
           * next remaining postponed job.
           */
          status = _Rate_monotonic_Block_while_expired(
            the_period,
            length,
            executing,
            &lock_context
          );
        }else{
          /*
           * Normal case that no postponed jobs and no expiration, so wait for
           * the period and update the deadline of watchdog accordingly.
           */
          status = _Rate_monotonic_Block_while_active(
            the_period,
            length,
            executing,
            &lock_context
          );
        }
        break;
      case RATE_MONOTONIC_INACTIVE:
        status = _Rate_monotonic_Activate(
          the_period,
          length,
          executing,
          &lock_context
        );
        break;
      default:
        /*
         * As now this period was already TIMEOUT, there must be at least one
         * postponed job recorded by the watchdog. The one which exceeded
         * the previous deadlines was just finished.
         *
         * Maybe there is more than one job postponed due to the preemption or
         * the previous finished job.
         */
        _Assert( state == RATE_MONOTONIC_EXPIRED );
        status = _Rate_monotonic_Block_while_expired(
          the_period,
          length,
          executing,
          &lock_context
        );
        break;
    }
  }

  return status;
}
/**
 *  @file
 *
 *  @brief Rate Monotonic Support
 *  @ingroup ClassicRateMon
 */

/*
 *  COPYRIGHT (c) 1989-2010.
 *  On-Line Applications Research Corporation (OAR).
 *  Copyright (c) 2016 embedded brains GmbH.
 *  COPYRIGHT (c) 2016 Kuan-Hsun Chen.
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/rtems/ratemonimpl.h>
#include <rtems/score/schedulerimpl.h>
#include <rtems/score/todimpl.h>
// TODO: the ")" at the end of the parameter list should be in a new line
// but it can't be modeled
// TODO: pointer alignement to the right is not supported (yet)
bool _Rate_monotonic_Get_status(
  const Rate_monotonic_Control* the_period,
  Timestamp_Control*            wall_since_last_period,
  Timestamp_Control*            cpu_since_last_period )
{
  Timestamp_Control uptime;
  Thread_Control*   owning_thread = the_period->owner;
  Timestamp_Control used;

  /*
   *  Determine elapsed wall time since period initiated.
   */
  _TOD_Get_uptime( &uptime );
  // TODO: Here the ");" cannot be placed in the next row by clang-format
  _Timestamp_Subtract(
    &the_period->time_period_initiated, &uptime, wall_since_last_period );

  /*
   *  Determine cpu usage since period initiated.
   */
  _Thread_Get_CPU_time_used( owning_thread, &used );

  /*
   *  The cpu usage info was reset while executing.  Can't
   *  determine a status.
   */
  if ( _Timestamp_Less_than( &used, &the_period->cpu_usage_period_initiated ) )
    return false;

  /* used = current cpu usage - cpu usage at start of period */
  // TODO: when a function call is split into multiple rows,
  // the function parameters should each be in a new row
  // can't be done with clang-format
  _Timestamp_Subtract(
    &the_period->cpu_usage_period_initiated, &used, cpu_since_last_period );

  return true;
}

static void _Rate_monotonic_Release_postponed_job(
  Rate_monotonic_Control* the_period,
  Thread_Control*         owner,
  rtems_interval          next_length,
  ISR_lock_Context*       lock_context )
{
  Per_CPU_Control*     cpu_self;
  Thread_queue_Context queue_context;

  --the_period->postponed_jobs;
  // TODO: clang-format does not always stick to the 80 column limit
  _Scheduler_Release_job(
    owner, &the_period->Priority, the_period->latest_deadline, &queue_context );

  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
  _Rate_monotonic_Release( the_period, lock_context );
  _Thread_Priority_update( &queue_context );
  _Thread_Dispatch_direct( cpu_self );
}

static void _Rate_monotonic_Release_job(
  Rate_monotonic_Control* the_period,
  Thread_Control*         owner,
  rtems_interval          next_length,
  ISR_lock_Context*       lock_context )
{
  Per_CPU_Control*     cpu_self;
  Thread_queue_Context queue_context;
  uint64_t             deadline;

  cpu_self = _Thread_Dispatch_disable_critical( lock_context );

  deadline = _Watchdog_Per_CPU_insert_ticks(
    &the_period->Timer, cpu_self, next_length );
  _Scheduler_Release_job(
    owner, &the_period->Priority, deadline, &queue_context );

  _Rate_monotonic_Release( the_period, lock_context );
  _Thread_Priority_update( &queue_context );
  _Thread_Dispatch_enable( cpu_self );
}

void _Rate_monotonic_Restart(
  Rate_monotonic_Control* the_period,
  Thread_Control*         owner,
  ISR_lock_Context*       lock_context )
{
  /*
   *  Set the starting point and the CPU time used for the statistics.
   */
  _TOD_Get_uptime( &the_period->time_period_initiated );
  _Thread_Get_CPU_time_used( owner, &the_period->cpu_usage_period_initiated );

  _Rate_monotonic_Release_job(
    the_period, owner, the_period->next_length, lock_context );
}
// TODO: can't turn off the break after function return type in this case
// although it is set to None in the .clang-format
// function parameters do not begin in a new row here
static void
_Rate_monotonic_Update_statistics( Rate_monotonic_Control* the_period )
{
  Timestamp_Control          executed;
  Timestamp_Control          since_last_period;
  Rate_monotonic_Statistics* stats;
  bool                       valid_status;

  /*
   *  Assume we are only called in states where it is appropriate
   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
   *  and RATE_MONOTONIC_EXPIRED.
   */

  /*
   *  Update the counts.
   */
  stats = &the_period->Statistics;
  stats->count++;

  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
    stats->missed_count++;

  /*
   *  Grab status for time statistics.
   */
  valid_status = _Rate_monotonic_Get_status(
    the_period, &since_last_period, &executed );
  if ( !valid_status )
    return;

  /*
   *  Update CPU time
   */
  _Timestamp_Add_to( &stats->total_cpu_time, &executed );

  if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
    stats->min_cpu_time = executed;

  if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
    stats->max_cpu_time = executed;

  /*
   *  Update Wall time
   */
  _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );

  if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
    stats->min_wall_time = since_last_period;

  if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
    stats->max_wall_time = since_last_period;
}

// same as above
static rtems_status_code
_Rate_monotonic_Get_status_for_state( rtems_rate_monotonic_period_states state )
{
  switch ( state ) {
    case RATE_MONOTONIC_INACTIVE:
      return RTEMS_NOT_DEFINED;
    case RATE_MONOTONIC_EXPIRED:
      return RTEMS_TIMEOUT;
    default:
      _Assert( state == RATE_MONOTONIC_ACTIVE );
      return RTEMS_SUCCESSFUL;
  }
}

static rtems_status_code _Rate_monotonic_Activate(
  Rate_monotonic_Control* the_period,
  rtems_interval          length,
  Thread_Control*         executing,
  ISR_lock_Context*       lock_context )
{
  the_period->postponed_jobs = 0;
  the_period->state = RATE_MONOTONIC_ACTIVE;
  the_period->next_length = length;
  _Rate_monotonic_Restart( the_period, executing, lock_context );
  return RTEMS_SUCCESSFUL;
}

static rtems_status_code _Rate_monotonic_Block_while_active(
  Rate_monotonic_Control* the_period,
  rtems_interval          length,
  Thread_Control*         executing,
  ISR_lock_Context*       lock_context )
{
  Per_CPU_Control* cpu_self;
  bool             success;

  /*
   *  Update statistics from the concluding period.
   */
  _Rate_monotonic_Update_statistics( the_period );

  /*
   *  This tells the _Rate_monotonic_Timeout that this task is
   *  in the process of blocking on the period and that we
   *  may be changing the length of the next period.
   */
  the_period->next_length = length;
  executing->Wait.return_argument = the_period;
  _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK );

  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
  _Rate_monotonic_Release( the_period, lock_context );

  _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );

  success = _Thread_Wait_flags_try_change_acquire(
    executing, RATE_MONOTONIC_INTEND_TO_BLOCK, RATE_MONOTONIC_BLOCKED );
  if ( !success ) {
    _Assert(
      _Thread_Wait_flags_get( executing ) == RATE_MONOTONIC_READY_AGAIN );
    _Thread_Unblock( executing );
  }

  _Thread_Dispatch_direct( cpu_self );
  return RTEMS_SUCCESSFUL;
}

/*
 * There are two possible cases: one is that the previous deadline is missed,
 * The other is that the number of postponed jobs is not 0, but the current
 * deadline is still not expired, i.e., state = RATE_MONOTONIC_ACTIVE.
 */
static rtems_status_code _Rate_monotonic_Block_while_expired(
  Rate_monotonic_Control* the_period,
  rtems_interval          length,
  Thread_Control*         executing,
  ISR_lock_Context*       lock_context )
{
  /*
   * No matter the just finished jobs in time or not,
   * they are actually missing their deadlines already.
   */
  the_period->state = RATE_MONOTONIC_EXPIRED;

  /*
   * Update statistics from the concluding period
   */
  _Rate_monotonic_Update_statistics( the_period );

  the_period->state = RATE_MONOTONIC_ACTIVE;
  the_period->next_length = length;

  _Rate_monotonic_Release_postponed_job(
    the_period, executing, length, lock_context );
  return RTEMS_TIMEOUT;
}

// TODO:same as above
rtems_status_code
rtems_rate_monotonic_period( rtems_id id, rtems_interval length )
{
  Rate_monotonic_Control*            the_period;
  ISR_lock_Context                   lock_context;
  Thread_Control*                    executing;
  rtems_status_code                  status;
  rtems_rate_monotonic_period_states state;

  the_period = _Rate_monotonic_Get( id, &lock_context );
  if ( the_period == NULL ) {
    return RTEMS_INVALID_ID;
  }

  executing = _Thread_Executing;
  if ( executing != the_period->owner ) {
    _ISR_lock_ISR_enable( &lock_context );
    return RTEMS_NOT_OWNER_OF_RESOURCE;
  }

  _Rate_monotonic_Acquire_critical( the_period, &lock_context );

  state = the_period->state;

  if ( length == RTEMS_PERIOD_STATUS ) {
    status = _Rate_monotonic_Get_status_for_state( state );
    _Rate_monotonic_Release( the_period, &lock_context );
  } else {
    switch ( state ) {
      case RATE_MONOTONIC_ACTIVE:

        if ( the_period->postponed_jobs > 0 ) {
          /*
           * If the number of postponed jobs is not 0, it means the
           * previous postponed instance is finished without exceeding
           * the current period deadline.
           *
           * Do nothing on the watchdog deadline assignment but release the
           * next remaining postponed job.
           */
           //TODO: the following arguments should all be in a seperate row
           // but they get put in one, when columnlimit is 80
          status = _Rate_monotonic_Block_while_expired(
            the_period, length, executing, &lock_context );
        } else {
          /*
           * Normal case that no postponed jobs and no expiration, so wait for
           * the period and update the deadline of watchdog accordingly.
           */
          status = _Rate_monotonic_Block_while_active(
            the_period, length, executing, &lock_context );
        }
        break;
      case RATE_MONOTONIC_INACTIVE:
        status = _Rate_monotonic_Activate(
          the_period, length, executing, &lock_context );
        break;
      default:
        /*
         * As now this period was already TIMEOUT, there must be at least one
         * postponed job recorded by the watchdog. The one which exceeded
         * the previous deadlines was just finished.
         *
         * Maybe there is more than one job postponed due to the preemption or
         * the previous finished job.
         */
        _Assert( state == RATE_MONOTONIC_EXPIRED );
        status = _Rate_monotonic_Block_while_expired(
          the_period, length, executing, &lock_context );
        break;
    }
  }

  return status;
}
_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to