Skip to content

Commit

Permalink
Implement thread scheduling
Browse files Browse the repository at this point in the history
  • Loading branch information
ljanyst committed Mar 2, 2016
1 parent 0aa2628 commit ee80953
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 5 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -14,6 +14,7 @@ add_library(
tb-tls.c
tb-mutexes.c
tb-cancel.c
tb-sched.c
tb-clone.S
tb-signal-trampoline.S)

Expand Down
4 changes: 4 additions & 0 deletions tb-private.h
Expand Up @@ -39,6 +39,10 @@

#define SIGCANCEL SIGRTMIN

#define TB_START_OK 0
#define TB_START_WAIT 1
#define TB_START_EXIT 2

void tb_tls_call_destructors();
void tb_cancel_handler(int sig, siginfo_t *si, void *ctx);
void tb_call_cleanup_handlers();
Expand Down
111 changes: 111 additions & 0 deletions tb-sched.c
@@ -0,0 +1,111 @@
//------------------------------------------------------------------------------
// Copyright (c) 2016 by Lukasz Janyst <lukasz@jany.st>
//------------------------------------------------------------------------------
// This file is part of thread-bites.
//
// thread-bites is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// thread-bites is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with thread-bites. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#include "tb.h"
#include "tb-private.h"

//------------------------------------------------------------------------------
// Set scheduling parameters
//------------------------------------------------------------------------------
struct tb_sched_param
{
int sched_priority;
};

int tbthread_setschedparam(tbthread_t thread, int policy, int priority)
{
if(policy != SCHED_NORMAL && policy != SCHED_FIFO && policy != SCHED_RR)
return -EINVAL;

if(priority < 0 || priority > 99)
return -EINVAL;

int ret = 0;
tbthread_mutex_lock(&desc_mutex);

if(!list_find_elem(&used_desc, thread)) {
ret = -ESRCH;
goto exit;
}

struct tb_sched_param p; p.sched_priority = priority;
ret = SYSCALL3(__NR_sched_setscheduler, thread->exit_futex, policy, &p);
if(!ret) {
thread->sched_policy = policy;
thread->sched_priority = priority;
}

exit:
tbthread_mutex_unlock(&desc_mutex);
return ret;
}

//------------------------------------------------------------------------------
// Get scheduling parameters
//------------------------------------------------------------------------------
int tbthread_getschedparam(tbthread_t thread, int *policy, int *priority)
{
int ret = 0;
tbthread_mutex_lock(&desc_mutex);

if(!list_find_elem(&used_desc, thread)) {
ret = -ESRCH;
goto exit;
}

*policy = thread->sched_policy;
*priority = thread->sched_priority;

exit:
tbthread_mutex_unlock(&desc_mutex);
return ret;
}

//------------------------------------------------------------------------------
// Set attribute scheduling policy
//------------------------------------------------------------------------------
int tbthread_attr_setschedpolicy(tbthread_attr_t *attr, int policy)
{
if(policy != SCHED_NORMAL && policy != SCHED_FIFO && policy != SCHED_RR)
return -EINVAL;
attr->sched_policy = policy;
return 0;
}

//------------------------------------------------------------------------------
// Get attribute scheduling priority
//------------------------------------------------------------------------------
int tbthread_attr_setschedpriority(tbthread_attr_t *attr, int priority)
{
if(priority < 0 || priority > 99)
return -EINVAL;
attr->sched_priority = priority;
}

//------------------------------------------------------------------------------
// Inherit scheduler attributes
//------------------------------------------------------------------------------
int tbthread_attr_setinheritsched(tbthread_attr_t *attr, int inheritsched)
{
if(inheritsched != TBTHREAD_INHERIT_SCHED &&
inheritsched != TBTHREAD_EXPLICIT_SCHED)
return -EINVAL;
attr->sched_inherit = inheritsched;
return 0;
}
64 changes: 59 additions & 5 deletions tb-threads.c
Expand Up @@ -48,8 +48,10 @@ void tbthread_init()
tbthread_t thread = malloc(sizeof(struct tbthread));
memset(thread, 0, sizeof(struct tbthread));
thread->self = thread;
thread->sched_policy = SCHED_NORMAL;
SYSCALL2(__NR_arch_prctl, ARCH_SET_FS, thread);
tb_pid = SYSCALL0(__NR_getpid);
thread->exit_futex = tb_pid;

struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
Expand All @@ -72,8 +74,10 @@ void tbthread_finit()
//------------------------------------------------------------------------------
void tbthread_attr_init(tbthread_attr_t *attr)
{
memset(attr, 0, sizeof(tbthread_attr_t));
attr->stack_size = 8192 * 1024;
attr->joinable = 1;
attr->sched_inherit = TBTHREAD_INHERIT_SCHED;
}

int tbthread_attr_setdetachstate(tbthread_attr_t *attr, int state)
Expand All @@ -90,6 +94,19 @@ int tbthread_attr_setdetachstate(tbthread_attr_t *attr, int state)
static int start_thread(void *arg)
{
tbthread_t th = (tbthread_t)arg;

//----------------------------------------------------------------------------
// Wait until we can run the user function
//----------------------------------------------------------------------------
if(th->start_status != TB_START_OK) {
SYSCALL3(__NR_futex, &th->start_status, FUTEX_WAIT, TB_START_WAIT);
if(th->start_status == TB_START_EXIT)
SYSCALL1(__NR_exit, 0);
}

//----------------------------------------------------------------------------
// Run the user function
//----------------------------------------------------------------------------
void *ret = th->fn(th->arg);
tbthread_setcancelstate(TBTHREAD_CANCEL_DISABLE, 0);
tb_clear_cleanup_handlers();
Expand Down Expand Up @@ -221,6 +238,9 @@ int tbthread_create(
void *(*f)(void *),
void *arg)
{
int ret = 0;
*thread = 0;

//----------------------------------------------------------------------------
// Allocate the stack with a guard page at the end so that we could protect
// from overflows (by receiving a SIGSEGV)
Expand All @@ -233,8 +253,8 @@ int tbthread_create(

status = SYSCALL3(__NR_mprotect, stack, EXEC_PAGESIZE, PROT_NONE);
if(status < 0) {
tbmunmap(stack, attr->stack_size);
return status;
ret = status;
goto error;
}

//----------------------------------------------------------------------------
Expand All @@ -250,6 +270,19 @@ int tbthread_create(
(*thread)->join_status = attr->joinable;
(*thread)->cancel_status = TB_CANCEL_ENABLED | TB_CANCEL_DEFERRED;

//----------------------------------------------------------------------------
// If we set a scheduling policy, we need to make sure that the thread goes to
// sleep immediately after it starts so that we can make sure that we can
// successfuly set the before the user function executes.
//----------------------------------------------------------------------------
if(!attr->sched_inherit)
(*thread)->start_status = TB_START_WAIT;
else {
tbthread_t self = tbthread_self();
(*thread)->sched_policy = self->sched_policy;
(*thread)->sched_priority = self->sched_priority;
}

//----------------------------------------------------------------------------
// Spawn the thread
//----------------------------------------------------------------------------
Expand All @@ -260,9 +293,8 @@ int tbthread_create(
int tid = tbclone(start_thread, *thread, flags, stack+attr->stack_size,
0, &(*thread)->exit_futex, *thread);
if(tid < 0) {
tbmunmap(stack, attr->stack_size);
free(*thread);
return tid;
ret = tid;
goto error;
}

//----------------------------------------------------------------------------
Expand All @@ -271,7 +303,29 @@ int tbthread_create(
//----------------------------------------------------------------------------
(*thread)->exit_futex = tid;

//----------------------------------------------------------------------------
// Set scheduling policy. If we succeed, we let the thread run. If not, we
// wait for it to exit;
//----------------------------------------------------------------------------
if(!attr->sched_inherit) {
ret = tbthread_setschedparam(*thread, attr->sched_policy,
attr->sched_priority);

if(ret) (*thread)->start_status = TB_START_EXIT;
else (*thread)->start_status = TB_START_OK;
SYSCALL3(__NR_futex, &(*thread)->start_status, FUTEX_WAKE, 1);

if(ret) {
wait_for_thread(*thread);
goto error;
}
}
return 0;

error:
tbmunmap(stack, attr->stack_size);
release_descriptor(*thread);
return ret;
}

//------------------------------------------------------------------------------
Expand Down
20 changes: 20 additions & 0 deletions tb.h
Expand Up @@ -25,6 +25,7 @@
#include <stddef.h>
#include <asm/signal.h>
#include <asm-generic/siginfo.h>
#include <linux/sched.h>

//------------------------------------------------------------------------------
// Constants
Expand All @@ -43,6 +44,9 @@

#define TBTHREAD_CANCELED ((void*)-1)

#define TBTHREAD_INHERIT_SCHED 1
#define TBTHREAD_EXPLICIT_SCHED 0

//------------------------------------------------------------------------------
// List struct
//------------------------------------------------------------------------------
Expand All @@ -59,6 +63,9 @@ typedef struct
{
uint32_t stack_size;
uint8_t joinable;
uint8_t sched_inherit;
uint8_t sched_policy;
uint8_t sched_priority;
} tbthread_attr_t;

//------------------------------------------------------------------------------
Expand All @@ -80,8 +87,11 @@ typedef struct tbthread
} tls[TBTHREAD_MAX_KEYS];
uint8_t join_status;
uint8_t cancel_status;
uint8_t sched_policy;
uint8_t sched_priority;
struct tbthread *joiner;
list_t cleanup_handlers;
uint32_t start_status;
} *tbthread_t;

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -158,6 +168,16 @@ int tbthread_mutex_lock(tbthread_mutex_t *mutex);
int tbthread_mutex_trylock(tbthread_mutex_t *mutex);
int tbthread_mutex_unlock(tbthread_mutex_t *mutex);

//------------------------------------------------------------------------------
// Scheduling
//------------------------------------------------------------------------------
int tbthread_setschedparam(tbthread_t thread, int policy, int priority);
int tbthread_getschedparam(tbthread_t thread, int *policy, int *priority);

int tbthread_attr_setschedpolicy(tbthread_attr_t *attr, int policy);
int tbthread_attr_setschedpriority(tbthread_attr_t *attr, int priority);
int tbthread_attr_setinheritsched(tbthread_attr_t *attr, int inheritsched);

//------------------------------------------------------------------------------
// Utility functions
//------------------------------------------------------------------------------
Expand Down

0 comments on commit ee80953

Please sign in to comment.