Changeset 9f1a034e in rtems


Ignore:
Timestamp:
Aug 8, 1996, 7:19:09 PM (25 years ago)
Author:
Mark Johannes <Mark.Johannes@…>
Branches:
4.10, 4.11, 4.8, 4.9, 5, master
Children:
e3515731
Parents:
77597dd
Message:

Init.c: added priority ceiling task cases.

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • c/src/tests/psxtests/psx05/init.c

    r77597dd r9f1a034e  
    3333  switch ( protocol ) {
    3434    case PTHREAD_PRIO_NONE:
    35       printf( "PTHREAD_PRIO_NONE\n" );
     35      puts( "PTHREAD_PRIO_NONE" );
    3636      break;
    3737    case PTHREAD_PRIO_INHERIT:
    38       printf( "PTHREAD_PRIO_INHERIT\n" );
     38      puts( "PTHREAD_PRIO_INHERIT" );
    3939      break;
    4040    case PTHREAD_PRIO_PROTECT:
    41       printf( "PTHREAD_PRIO_PROTECT\n" );
     41      puts( "PTHREAD_PRIO_PROTECT" );
    4242      break;
    4343    default:
    44       printf( "UNKNOWN\n" );
     44      puts( "UNKNOWN" );
    4545      assert( 0 );
    4646      break;
     
    6060  switch ( pshared ) {
    6161    case PTHREAD_PROCESS_PRIVATE:
    62       printf( "PTHREAD_PROCESS_PRIVATE\n" );
     62      puts( "PTHREAD_PROCESS_PRIVATE" );
    6363      break;
    6464    case PTHREAD_PROCESS_SHARED:
    65       printf( "PTHREAD_PROCESS_SHARED\n" );
     65      puts( "PTHREAD_PROCESS_SHARED" );
    6666      break;
    6767    default:
    68       printf( "UNKNOWN\n" );
     68      puts( "UNKNOWN" );
    6969      assert( 0 );
    7070      break;
     
    7979  pthread_mutexattr_t  attr;
    8080  struct timespec      times;
     81  struct sched_param   param;
     82  int                  policy;
     83  int                  ceiling;
     84  int                  old_ceiling;
    8185
    8286  puts( "\n\n*** POSIX TEST 5 ***" );
     
    9397  /* basic checkout of mutex attributes */
    9498
    95   printf( "Init: Initializing mutex attributes\n" );
     99  puts( "Init: Initializing mutex attributes" );
    96100  status = pthread_mutexattr_init( &attr );
    97101  assert( !status );
     
    99103  Print_mutexattr( "Init: ", &attr );
    100104
    101   printf( "Init: Changing mutex attributes\n" );
     105  puts( "Init: Changing mutex attributes" );
    102106  status = pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_INHERIT );
    103107  assert( !status );
     
    111115  Print_mutexattr( "Init: ", &attr );
    112116
    113   printf( "Init: Resetting mutex attributes\n" );
     117  puts( "Init: Resetting mutex attributes" );
    114118  status = pthread_mutexattr_init( &attr );
    115119  assert( !status );
     
    117121  /* create a thread */
    118122
    119   status = pthread_create( &Task_id, NULL, Task_1_through_3, NULL );
     123  status = pthread_create( &Task_id, NULL, Task_1, NULL );
    120124  assert( !status );
    121125
     
    124128  empty_line();
    125129
    126   printf( "Init: Creating a mutex\n" );
     130  puts( "Init: Creating a mutex" );
    127131  status = pthread_mutex_init( &Mutex_id, &attr );
    128132  if ( status )
     
    130134  assert( !status );
    131135
    132   printf( "Init: pthread_mutex_trylock successfully\n" );
     136  puts( "Init: pthread_mutex_trylock successfully" );
    133137  status = pthread_mutex_trylock( &Mutex_id );
    134138  if ( status )
     
    136140  assert( !status );
    137141
    138   printf( "Init: pthread_mutex_trylock already locked\n" );
     142  puts( "Init: pthread_mutex_trylock already locked" );
    139143  status = pthread_mutex_trylock( &Mutex_id );
    140144  if ( status != EDEADLK )
     
    142146  assert( status == EDEADLK );
    143147
    144   printf( "Init: pthread_mutex_lock already locked\n" );
     148  puts( "Init: pthread_mutex_lock already locked" );
    145149  status = pthread_mutex_lock( &Mutex_id );
    146150  if ( status != EDEADLK )
     
    148152  assert( status == EDEADLK );
    149153
    150   printf( "Init: Sleep 1 second\n" );
     154  puts( "Init: Sleep 1 second" );
    151155
    152156  sleep( 1 );
     
    154158     /* switch to task 1 */
    155159
    156   printf( "Init: pthread_mutex_unlock successfully\n" );
     160  puts( "Init: pthread_mutex_unlock successfully" );
    157161  status = pthread_mutex_unlock( &Mutex_id );
    158162  if ( status )
     
    160164  assert( !status );
    161165
    162   printf( "Init: pthread_mutex_unlock not owner\n" );
     166  puts( "Init: pthread_mutex_unlock not owner" );
    163167  status = pthread_mutex_unlock( &Mutex_id );
    164168  if ( status != EPERM )
     
    168172  times.tv_sec = 0;
    169173  times.tv_nsec = 500000000;
    170   printf( "Init: pthread_mutex_timedlock time out in 1/2 second\n" );
     174  puts( "Init: pthread_mutex_timedlock time out in 1/2 second" );
    171175  status = pthread_mutex_timedlock( &Mutex_id, &times );
    172176  if ( status != EAGAIN )
     
    176180     /* switch to idle */
    177181
    178   printf( "Init: correctly timed out waiting for mutex\n" );
     182  puts( "Init: correctly timed out waiting for mutex" );
     183
     184  /* destroy a mutex */
     185
     186  empty_line();
     187
     188  puts( "Init: Creating a mutex" );
     189  status = pthread_mutex_init( &Mutex2_id, &attr );
     190  if ( status )
     191    printf( "status = %d\n", status );
     192  assert( !status );
     193
     194  puts( "Init: pthread_mutexattr_destroy" );
     195  status = pthread_mutexattr_destroy( &attr );
     196  assert( !status );
     197
     198  puts( "Init: pthread_mutex_destroy" );
     199  status = pthread_mutex_destroy( &Mutex2_id );
     200  assert( !status );
     201 
     202  /* destroy a busy mutex */
     203 
     204  empty_line();
     205 
     206  puts( "Init: Initializing mutex attributes" );
     207  status = pthread_mutexattr_init( &attr );
     208  assert( !status );
     209
     210  puts( "Init: Creating a mutex" );
     211  status = pthread_mutex_init( &Mutex2_id, &attr );
     212  assert( !status );
     213 
     214  puts( "Init: pthread_mutex_trylock successfully" );
     215  status = pthread_mutex_trylock( &Mutex2_id );
     216  if ( status )
     217    printf( "status = %d\n", status );
     218  assert( !status );
     219
     220  status = pthread_mutex_destroy( &Mutex2_id );
     221  if ( status != EBUSY )
     222    printf( "status = %d\n", status );
     223  assert( status == EBUSY );
     224  puts( "Init: pthread_mutex_destroy - EBUSY" );
     225
     226  puts( "Init: pthread_mutex_unlock successfully" );
     227  status = pthread_mutex_unlock( &Mutex2_id );
     228  assert( !status );
     229
     230  puts( "Init: pthread_mutex_destroy" );
     231  status = pthread_mutex_destroy( &Mutex2_id );
     232  assert( !status );
     233
     234  /* priority inherit mutex */
     235
     236  empty_line();
     237 
     238  puts( "Init: Initializing mutex attributes" );
     239  status = pthread_mutexattr_init( &attr );
     240  assert( !status );
     241
     242  puts( "Init: Setting PTHREAD_PRIO_INHERIT attribute" );
     243  status = pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_INHERIT );
     244  assert( !status );
     245
     246  puts( "Init: Creating a mutex" );
     247  status = pthread_mutex_init( &Mutex2_id, &attr );
     248  assert( !status );
     249
     250  puts( "Init: pthread_mutex_trylock successfully" );
     251  status = pthread_mutex_trylock( &Mutex2_id );
     252  assert( !status );
     253
     254  /* create a thread at a lower priority */
     255 
     256  status = pthread_create( &Task2_id, NULL, Task_2, NULL );
     257  assert( !status );
     258 
     259  /* set priority of Task2 to highest priority */
     260 
     261  param.sched_priority = 255;
     262 
     263  puts( "Init: Setting Task2 priority to highest" );
     264  status = pthread_setschedparam( Task2_id, SCHED_FIFO, &param );
     265  assert( !status );
     266
     267  /* switching to Task2 */
     268
     269  status = pthread_getschedparam( pthread_self(), &policy, &param );
     270  assert( !status );
     271  printf( "Init: pthread_getschedparam priority = %d\n", param.sched_priority );
     272
     273  puts( "Init: pthread_mutex_unlock successfully" );
     274  status = pthread_mutex_unlock( &Mutex2_id );
     275  assert( !status );
     276 
     277  puts( "Init: pthread_mutexattr_destroy" );
     278  status = pthread_mutexattr_destroy( &attr );
     279  assert( !status );
     280
     281  puts( "Init: pthread_mutex_destroy" );
     282  status = pthread_mutex_destroy( &Mutex2_id );
     283  assert( !status );
     284 
     285  /* priority ceiling mutex */
     286 
     287  empty_line();
     288 
     289  puts( "Init: Initializing mutex attributes" );
     290  status = pthread_mutexattr_init( &attr );
     291  assert( !status );
     292 
     293  puts( "Init: Setting PTHREAD_PRIO_PROTECT attribute" );
     294  status = pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_PROTECT );
     295  assert( !status );
     296 
     297  puts( "Init: Creating a mutex" );
     298  status = pthread_mutex_init( &Mutex2_id, &attr );
     299  assert( !status );
     300 
     301  status = pthread_mutex_getprioceiling( &Mutex2_id, &ceiling );
     302  assert( !status );
     303  printf( "Init: priority ceiling = %d\n", ceiling );
     304 
     305  status = pthread_mutex_setprioceiling( &Mutex2_id, 200, &old_ceiling );
     306  assert( !status );
     307  printf( "Init: Set ceiling = 200  old priority ceiling = %d\n",old_ceiling );
     308 
     309  status = pthread_getschedparam( pthread_self(), &policy, &param );
     310  assert( !status );
     311  printf( "Init: pthread_getschedparam priority = %d\n", param.sched_priority );
     312
     313  puts( "Init: pthread_mutex_trylock successfully" );
     314  status = pthread_mutex_trylock( &Mutex2_id );
     315  assert( !status );
     316 
     317  status = pthread_getschedparam( pthread_self(), &policy, &param );
     318  assert( !status );
     319  printf( "Init: pthread_getschedparam priority = %d\n", param.sched_priority );
     320
     321  /* create a thread at a higher priority */
     322 
     323  status = pthread_create( &Task3_id, NULL, Task_3, NULL );
     324  assert( !status );
     325 
     326  /* set priority of Task3 to highest priority */
     327 
     328  param.sched_priority = 199;
     329 
     330  status = pthread_setschedparam( Task3_id, SCHED_FIFO, &param );
     331  assert( !status );
     332  puts( "Init: Set Task3 priority to highest" );
     333 
     334  /* DOES NOT SWITCH to Task3 */
     335
     336  puts( "Init: Sleep 1 second" );
     337  assert( !status );
     338  sleep( 1 );
     339 
     340  /* switch to task 3 */
     341 
     342  puts( "Init: pthread_mutex_unlock successfully" );
     343  status = pthread_mutex_unlock( &Mutex2_id );
     344  assert( !status );
     345 
     346  status = pthread_mutex_getprioceiling( &Mutex2_id, &ceiling );
     347  assert( !status );
     348  printf( "Init: priority ceiling = %d\n", ceiling );
     349 
     350  /* set priority of Init to highest priority */
     351 
     352  param.sched_priority = 255;
     353 
     354  status = pthread_setschedparam( Init_id, SCHED_FIFO, &param );
     355  assert( !status );
     356  puts( "Init: Set Init priority to highest" );
     357 
     358  status = pthread_mutex_lock( &Mutex2_id );
     359  if ( status != EDEADLK )
     360    printf( "status = %d\n", status );
     361  assert( status == EINVAL );
     362  puts( "Init: pthread_mutex_lock EINVAL (priority ceiling violation)" );
    179363
    180364  puts( "*** END OF POSIX TEST 5 ***" );
  • testsuites/psxtests/psx05/init.c

    r77597dd r9f1a034e  
    3333  switch ( protocol ) {
    3434    case PTHREAD_PRIO_NONE:
    35       printf( "PTHREAD_PRIO_NONE\n" );
     35      puts( "PTHREAD_PRIO_NONE" );
    3636      break;
    3737    case PTHREAD_PRIO_INHERIT:
    38       printf( "PTHREAD_PRIO_INHERIT\n" );
     38      puts( "PTHREAD_PRIO_INHERIT" );
    3939      break;
    4040    case PTHREAD_PRIO_PROTECT:
    41       printf( "PTHREAD_PRIO_PROTECT\n" );
     41      puts( "PTHREAD_PRIO_PROTECT" );
    4242      break;
    4343    default:
    44       printf( "UNKNOWN\n" );
     44      puts( "UNKNOWN" );
    4545      assert( 0 );
    4646      break;
     
    6060  switch ( pshared ) {
    6161    case PTHREAD_PROCESS_PRIVATE:
    62       printf( "PTHREAD_PROCESS_PRIVATE\n" );
     62      puts( "PTHREAD_PROCESS_PRIVATE" );
    6363      break;
    6464    case PTHREAD_PROCESS_SHARED:
    65       printf( "PTHREAD_PROCESS_SHARED\n" );
     65      puts( "PTHREAD_PROCESS_SHARED" );
    6666      break;
    6767    default:
    68       printf( "UNKNOWN\n" );
     68      puts( "UNKNOWN" );
    6969      assert( 0 );
    7070      break;
     
    7979  pthread_mutexattr_t  attr;
    8080  struct timespec      times;
     81  struct sched_param   param;
     82  int                  policy;
     83  int                  ceiling;
     84  int                  old_ceiling;
    8185
    8286  puts( "\n\n*** POSIX TEST 5 ***" );
     
    9397  /* basic checkout of mutex attributes */
    9498
    95   printf( "Init: Initializing mutex attributes\n" );
     99  puts( "Init: Initializing mutex attributes" );
    96100  status = pthread_mutexattr_init( &attr );
    97101  assert( !status );
     
    99103  Print_mutexattr( "Init: ", &attr );
    100104
    101   printf( "Init: Changing mutex attributes\n" );
     105  puts( "Init: Changing mutex attributes" );
    102106  status = pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_INHERIT );
    103107  assert( !status );
     
    111115  Print_mutexattr( "Init: ", &attr );
    112116
    113   printf( "Init: Resetting mutex attributes\n" );
     117  puts( "Init: Resetting mutex attributes" );
    114118  status = pthread_mutexattr_init( &attr );
    115119  assert( !status );
     
    117121  /* create a thread */
    118122
    119   status = pthread_create( &Task_id, NULL, Task_1_through_3, NULL );
     123  status = pthread_create( &Task_id, NULL, Task_1, NULL );
    120124  assert( !status );
    121125
     
    124128  empty_line();
    125129
    126   printf( "Init: Creating a mutex\n" );
     130  puts( "Init: Creating a mutex" );
    127131  status = pthread_mutex_init( &Mutex_id, &attr );
    128132  if ( status )
     
    130134  assert( !status );
    131135
    132   printf( "Init: pthread_mutex_trylock successfully\n" );
     136  puts( "Init: pthread_mutex_trylock successfully" );
    133137  status = pthread_mutex_trylock( &Mutex_id );
    134138  if ( status )
     
    136140  assert( !status );
    137141
    138   printf( "Init: pthread_mutex_trylock already locked\n" );
     142  puts( "Init: pthread_mutex_trylock already locked" );
    139143  status = pthread_mutex_trylock( &Mutex_id );
    140144  if ( status != EDEADLK )
     
    142146  assert( status == EDEADLK );
    143147
    144   printf( "Init: pthread_mutex_lock already locked\n" );
     148  puts( "Init: pthread_mutex_lock already locked" );
    145149  status = pthread_mutex_lock( &Mutex_id );
    146150  if ( status != EDEADLK )
     
    148152  assert( status == EDEADLK );
    149153
    150   printf( "Init: Sleep 1 second\n" );
     154  puts( "Init: Sleep 1 second" );
    151155
    152156  sleep( 1 );
     
    154158     /* switch to task 1 */
    155159
    156   printf( "Init: pthread_mutex_unlock successfully\n" );
     160  puts( "Init: pthread_mutex_unlock successfully" );
    157161  status = pthread_mutex_unlock( &Mutex_id );
    158162  if ( status )
     
    160164  assert( !status );
    161165
    162   printf( "Init: pthread_mutex_unlock not owner\n" );
     166  puts( "Init: pthread_mutex_unlock not owner" );
    163167  status = pthread_mutex_unlock( &Mutex_id );
    164168  if ( status != EPERM )
     
    168172  times.tv_sec = 0;
    169173  times.tv_nsec = 500000000;
    170   printf( "Init: pthread_mutex_timedlock time out in 1/2 second\n" );
     174  puts( "Init: pthread_mutex_timedlock time out in 1/2 second" );
    171175  status = pthread_mutex_timedlock( &Mutex_id, &times );
    172176  if ( status != EAGAIN )
     
    176180     /* switch to idle */
    177181
    178   printf( "Init: correctly timed out waiting for mutex\n" );
     182  puts( "Init: correctly timed out waiting for mutex" );
     183
     184  /* destroy a mutex */
     185
     186  empty_line();
     187
     188  puts( "Init: Creating a mutex" );
     189  status = pthread_mutex_init( &Mutex2_id, &attr );
     190  if ( status )
     191    printf( "status = %d\n", status );
     192  assert( !status );
     193
     194  puts( "Init: pthread_mutexattr_destroy" );
     195  status = pthread_mutexattr_destroy( &attr );
     196  assert( !status );
     197
     198  puts( "Init: pthread_mutex_destroy" );
     199  status = pthread_mutex_destroy( &Mutex2_id );
     200  assert( !status );
     201 
     202  /* destroy a busy mutex */
     203 
     204  empty_line();
     205 
     206  puts( "Init: Initializing mutex attributes" );
     207  status = pthread_mutexattr_init( &attr );
     208  assert( !status );
     209
     210  puts( "Init: Creating a mutex" );
     211  status = pthread_mutex_init( &Mutex2_id, &attr );
     212  assert( !status );
     213 
     214  puts( "Init: pthread_mutex_trylock successfully" );
     215  status = pthread_mutex_trylock( &Mutex2_id );
     216  if ( status )
     217    printf( "status = %d\n", status );
     218  assert( !status );
     219
     220  status = pthread_mutex_destroy( &Mutex2_id );
     221  if ( status != EBUSY )
     222    printf( "status = %d\n", status );
     223  assert( status == EBUSY );
     224  puts( "Init: pthread_mutex_destroy - EBUSY" );
     225
     226  puts( "Init: pthread_mutex_unlock successfully" );
     227  status = pthread_mutex_unlock( &Mutex2_id );
     228  assert( !status );
     229
     230  puts( "Init: pthread_mutex_destroy" );
     231  status = pthread_mutex_destroy( &Mutex2_id );
     232  assert( !status );
     233
     234  /* priority inherit mutex */
     235
     236  empty_line();
     237 
     238  puts( "Init: Initializing mutex attributes" );
     239  status = pthread_mutexattr_init( &attr );
     240  assert( !status );
     241
     242  puts( "Init: Setting PTHREAD_PRIO_INHERIT attribute" );
     243  status = pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_INHERIT );
     244  assert( !status );
     245
     246  puts( "Init: Creating a mutex" );
     247  status = pthread_mutex_init( &Mutex2_id, &attr );
     248  assert( !status );
     249
     250  puts( "Init: pthread_mutex_trylock successfully" );
     251  status = pthread_mutex_trylock( &Mutex2_id );
     252  assert( !status );
     253
     254  /* create a thread at a lower priority */
     255 
     256  status = pthread_create( &Task2_id, NULL, Task_2, NULL );
     257  assert( !status );
     258 
     259  /* set priority of Task2 to highest priority */
     260 
     261  param.sched_priority = 255;
     262 
     263  puts( "Init: Setting Task2 priority to highest" );
     264  status = pthread_setschedparam( Task2_id, SCHED_FIFO, &param );
     265  assert( !status );
     266
     267  /* switching to Task2 */
     268
     269  status = pthread_getschedparam( pthread_self(), &policy, &param );
     270  assert( !status );
     271  printf( "Init: pthread_getschedparam priority = %d\n", param.sched_priority );
     272
     273  puts( "Init: pthread_mutex_unlock successfully" );
     274  status = pthread_mutex_unlock( &Mutex2_id );
     275  assert( !status );
     276 
     277  puts( "Init: pthread_mutexattr_destroy" );
     278  status = pthread_mutexattr_destroy( &attr );
     279  assert( !status );
     280
     281  puts( "Init: pthread_mutex_destroy" );
     282  status = pthread_mutex_destroy( &Mutex2_id );
     283  assert( !status );
     284 
     285  /* priority ceiling mutex */
     286 
     287  empty_line();
     288 
     289  puts( "Init: Initializing mutex attributes" );
     290  status = pthread_mutexattr_init( &attr );
     291  assert( !status );
     292 
     293  puts( "Init: Setting PTHREAD_PRIO_PROTECT attribute" );
     294  status = pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_PROTECT );
     295  assert( !status );
     296 
     297  puts( "Init: Creating a mutex" );
     298  status = pthread_mutex_init( &Mutex2_id, &attr );
     299  assert( !status );
     300 
     301  status = pthread_mutex_getprioceiling( &Mutex2_id, &ceiling );
     302  assert( !status );
     303  printf( "Init: priority ceiling = %d\n", ceiling );
     304 
     305  status = pthread_mutex_setprioceiling( &Mutex2_id, 200, &old_ceiling );
     306  assert( !status );
     307  printf( "Init: Set ceiling = 200  old priority ceiling = %d\n",old_ceiling );
     308 
     309  status = pthread_getschedparam( pthread_self(), &policy, &param );
     310  assert( !status );
     311  printf( "Init: pthread_getschedparam priority = %d\n", param.sched_priority );
     312
     313  puts( "Init: pthread_mutex_trylock successfully" );
     314  status = pthread_mutex_trylock( &Mutex2_id );
     315  assert( !status );
     316 
     317  status = pthread_getschedparam( pthread_self(), &policy, &param );
     318  assert( !status );
     319  printf( "Init: pthread_getschedparam priority = %d\n", param.sched_priority );
     320
     321  /* create a thread at a higher priority */
     322 
     323  status = pthread_create( &Task3_id, NULL, Task_3, NULL );
     324  assert( !status );
     325 
     326  /* set priority of Task3 to highest priority */
     327 
     328  param.sched_priority = 199;
     329 
     330  status = pthread_setschedparam( Task3_id, SCHED_FIFO, &param );
     331  assert( !status );
     332  puts( "Init: Set Task3 priority to highest" );
     333 
     334  /* DOES NOT SWITCH to Task3 */
     335
     336  puts( "Init: Sleep 1 second" );
     337  assert( !status );
     338  sleep( 1 );
     339 
     340  /* switch to task 3 */
     341 
     342  puts( "Init: pthread_mutex_unlock successfully" );
     343  status = pthread_mutex_unlock( &Mutex2_id );
     344  assert( !status );
     345 
     346  status = pthread_mutex_getprioceiling( &Mutex2_id, &ceiling );
     347  assert( !status );
     348  printf( "Init: priority ceiling = %d\n", ceiling );
     349 
     350  /* set priority of Init to highest priority */
     351 
     352  param.sched_priority = 255;
     353 
     354  status = pthread_setschedparam( Init_id, SCHED_FIFO, &param );
     355  assert( !status );
     356  puts( "Init: Set Init priority to highest" );
     357 
     358  status = pthread_mutex_lock( &Mutex2_id );
     359  if ( status != EDEADLK )
     360    printf( "status = %d\n", status );
     361  assert( status == EINVAL );
     362  puts( "Init: pthread_mutex_lock EINVAL (priority ceiling violation)" );
    179363
    180364  puts( "*** END OF POSIX TEST 5 ***" );
Note: See TracChangeset for help on using the changeset viewer.