summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src/pthreadsetschedprio.c
blob: fac86d2609137cfa9c8e2418e5a455b24870f480 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/*
 * Copyright (c) 2016 embedded brains GmbH
 *
 * 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 <pthread.h>
#include <errno.h>

#include <rtems/posix/priorityimpl.h>
#include <rtems/posix/threadsup.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/schedulerimpl.h>

typedef struct {
  int prio;
  int error;
} POSIX_Set_sched_prio_context;

static bool _POSIX_Set_sched_prio_filter(
  Thread_Control   *the_thread,
  Priority_Control *new_priority_p,
  void             *arg
)
{
  POSIX_Set_sched_prio_context *context;
  int                           prio;
  const Scheduler_Control      *scheduler;
  POSIX_API_Control            *api;
  bool                          valid;
  Priority_Control              current_priority;
  Priority_Control              new_priority;

  context = arg;
  prio = context->prio;
  scheduler = _Scheduler_Get_own( the_thread );

  new_priority = _POSIX_Priority_To_core( scheduler, prio, &valid );
  if ( !valid ) {
    context->error = EINVAL;
    return false;
  }

  *new_priority_p = new_priority;

  current_priority = _Thread_Get_priority( the_thread );
  the_thread->real_priority = new_priority;

  api = the_thread->API_Extensions[ THREAD_API_POSIX ];

  api->Sporadic.high_priority = new_priority;

  if ( api->Sporadic.low_priority < new_priority ) {
    api->Sporadic.low_priority  = new_priority;
  }

  context->error = 0;
  return _Thread_Priority_less_than( current_priority, new_priority )
    || !_Thread_Owns_resources( the_thread );
}

int pthread_setschedprio( pthread_t thread, int prio )
{
  Thread_Control               *the_thread;
  Per_CPU_Control              *cpu_self;
  POSIX_Set_sched_prio_context  context;
  ISR_lock_Context              lock_context;

  context.prio = prio;

  the_thread = _Thread_Get( thread, &lock_context );

  if ( the_thread == NULL ) {
    return ESRCH;
  }

  cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
  _ISR_lock_ISR_enable( &lock_context );

  _Thread_Change_priority(
    the_thread,
    0,
    &context,
    _POSIX_Set_sched_prio_filter,
    true
  );

  _Thread_Dispatch_enable( cpu_self );
  return context.error;
}