Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix RR scheduler and mutex/cond #36

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ deps := $(OBJS:%.o=.%.o.d)

.PHONY: all check clean distclean

all: $(CMSIS)/$(PLAT) $(NAME).lds $(NAME).bin
all: FORCE $(CMSIS)/$(PLAT) $(NAME).lds $(NAME).bin

# generic build rules
include mk/flags.mk
Expand Down Expand Up @@ -73,3 +73,5 @@ distclean: clean
include platform/$(PLAT)/build.mk

-include $(deps)

FORCE:
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,17 @@ $ python -m tests
# Run partial test with command line tools
$ python -m tests fs_1 cond_2
```

## Makefile

You can switch scheduler by makefile flags:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make scheduler pluggable as Linux does instead of configuring it at build time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to change scheduler in runtime using sched_select for now. But this is an easy step for running test and debugging.


```
# Using bitmap scheduler

$ make SCHED=BITMAP

# Using RR scheduler

$ make SCHED=RR
```
4 changes: 2 additions & 2 deletions include/kernel/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ struct thread_info;
#define SCHED_OPT_TICK 3

struct sched {
int (*init)(void);
int (*init)(struct thread_info *thread);
int (*enqueue)(struct thread_info *thread);
int (*dequeue)(struct thread_info *thread);
int (*elect)(int switch_type);
};

int sched_select(int sched_type);
int sched_select(int sched_type, struct thread_info *thread);
int sched_enqueue(struct thread_info *thread);
int sched_dequeue(struct thread_info *thread);
int sched_elect(int flags);
Expand Down
2 changes: 2 additions & 0 deletions include/kernel/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ struct thread_info {
struct list_head ti_list; /* global list of threads */
struct list_head ti_q; /* shared by sched runq, mutex waitq, thread joinq */

int ti_queued; /* in runqueue */

/* http://www.domaigne.com/blog/computing/joinable-and-detached-threads/ */
void *ti_retval;
int ti_detached;
Expand Down
1 change: 1 addition & 0 deletions kernel/cond.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ int sys_pthread_cond_wait(pthread_cond_t *cond, kernel_mutex_t *mutex)
CURRENT_THREAD_INFO(curr_thread);
curr_thread->ti_private = cond;
curr_thread->ti_state = THREAD_STATE_BLOCKED;
sched_dequeue(curr_thread);
list_add_tail(&curr_thread->ti_q, &cond_head);
sys_pthread_mutex_unlock(mutex);

Expand Down
11 changes: 8 additions & 3 deletions kernel/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ void init_IRQ(void);
struct task_info idle_task;
struct task_info main_task;

/* Select scheduler */
#ifndef SCHED_CLASS
#define SCHED_CLASS SCHED_CLASS_BITMAP
#endif

void print_version(void)
{
char buf[] = {0, 0};
Expand Down Expand Up @@ -130,9 +135,6 @@ struct thread_info *start_kernel(void)
show_page_bitmap(); // init_pages();
kmem_cache_init();

/* select a scheduling policy */
sched_select(SCHED_CLASS_BITMAP);

/* idle_thread is not added to the runqueue */
task_init(&idle_task);
thread_idle =
Expand All @@ -156,6 +158,9 @@ struct thread_info *start_kernel(void)
printk("Created main_thread at <%p> with priority=%d\n", thread_main,
thread_main->ti_priority);

/* select a scheduling policy */
sched_select(SCHED_CLASS, thread_main);

/* Reclaim the early-stack physical memory. In the current context, no
* page allocation after this point are allowed. */
printk("Reclaim early stack's physical memory (%d Bytes, order=%d).\n",
Expand Down
1 change: 1 addition & 0 deletions kernel/mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ int sys_pthread_mutex_lock(kernel_mutex_t *mutex)
CURRENT_THREAD_INFO(curr_thread);
curr_thread->ti_private = mutex;
curr_thread->ti_state = THREAD_STATE_BLOCKED;
sched_dequeue(curr_thread);
list_add_tail(&curr_thread->ti_q, &mutex_head);
sched_elect(SCHED_OPT_NONE);

Expand Down
8 changes: 6 additions & 2 deletions kernel/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@ extern const struct sched sched_bitmap;

static const struct sched *sched;

int sched_select(int sched_type)
int sched_select(int sched_type, struct thread_info *thread)
{
printk("Scheduler: ");
switch (sched_type) {
case SCHED_CLASS_RR:
printk("Round-Robin\n");
sched = &sched_rr;
break;
case SCHED_CLASS_BITMAP:
printk("Bitmap\n");
sched = &sched_bitmap;
break;
default:
printk("Unknown");
return -1;
}

return sched->init();
return sched->init(thread);
}

int sched_enqueue(struct thread_info *thread)
Expand Down
2 changes: 1 addition & 1 deletion kernel/sched/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ static struct {
.expire = &_expire,
};

static int sched_bitmap_init(void)
static int sched_bitmap_init(__unused struct thread_info *thread)
{
INIT_BITMAP(sched_struct.active);
INIT_BITMAP(sched_struct.expire);
Expand Down
63 changes: 25 additions & 38 deletions kernel/sched/rr.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,74 +7,61 @@
static LIST_HEAD(rr_runq);
extern struct thread_info *thread_idle;

int sched_rr_init(void)
int sched_rr_init(struct thread_info *thread)
{
if (thread)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we initialize without checking thread? That is, we can explicitly arrange the order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not check about thread is NULL or not (or maybe checking the type is struct thread_info), is there any benefit to put a NULL into runqueue?

sched_rr_enqueue(thread);
return 0;
}

static struct thread_info *find_next_thread(struct thread_info *thread)
static struct thread_info *find_next_thread(void)
{
if (list_is_last(&thread->ti_q, &rr_runq))
return list_first_entry(&rr_runq, struct thread_info, ti_q);

return list_next_entry(thread, ti_q);
return list_first_entry(&rr_runq, struct thread_info, ti_q);
}

int sched_rr_enqueue(struct thread_info *thread)
{
list_add(&thread->ti_q, &rr_runq);
if (thread->ti_queued)
return -1;

list_add_tail(&thread->ti_q, &rr_runq);
thread->ti_queued = 1;

return 0;
}

int sched_rr_dequeue(struct thread_info *thread)
{
CURRENT_THREAD_INFO(current);
if (!thread->ti_queued)
return -1;

if (current == thread) {
struct thread_info *next = thread_idle;
if (!list_is_singular(&rr_runq)) {
next = find_next_thread(current);
}
list_del(&thread->ti_q);
thread_restore(next); // FIXME: rename to switch_to_no_save
} else {
list_del(&thread->ti_q);
}
list_del(&thread->ti_q);
thread->ti_queued = 0;

return 0;
}

/* This function is used when the runqueue has been modified externally, and it
is not possible to fetch the next thread. */
static int sched_rr_elect_reset(void)
void sched_rr_requeue(struct thread_info *thread)
{
CURRENT_THREAD_INFO(current);
struct thread_info *next = thread_idle;

if (!list_empty(&rr_runq))
next = list_first_entry(&rr_runq, struct thread_info, ti_q);
switch_to(next, current);

return 0;
sched_rr_dequeue(thread);
sched_rr_enqueue(thread);
}

int sched_rr_elect(int switch_type)
int sched_rr_elect(__unused int switch_type)
{
CURRENT_THREAD_INFO(current);
struct thread_info *next;

if (switch_type & SCHED_OPT_RESET)
return sched_rr_elect_reset();

if (list_empty(&rr_runq)) {
// go to thread idle.
next = thread_idle;
} else {
next = find_next_thread(current);
switch_to(thread_idle, current);
return -1;
}

/* keep running the previous thread */
/* XXX: Will RR stuck inside the loop? */
while ((next = find_next_thread()) == current && !list_is_singular(&rr_runq))
sched_rr_requeue(next);

/* Shortcut if next is current */
if (next == current)
return -1;

Expand Down
24 changes: 12 additions & 12 deletions libc/v7m-pthread.S
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ ENTRY(pthread_mutex_lock)
bne 0b
dmb @ ARMv7-M ARM, A3.4.6
movs r0, #0 @ it also update EQ flag
1: itt ne
movne r1, #SYS_PTHREAD_MUTEX_LOCK
svcne #1
bx lr
1: beq 2f
mov r1, #SYS_PTHREAD_MUTEX_LOCK
svc #1
2: bx lr
ENDPROC(pthread_mutex_lock)

@ int pthread_mutex_trylock(pthread_mutex_t *mutex)
Expand All @@ -38,9 +38,9 @@ ENTRY(pthread_mutex_trylock)
teq r1, #0 @ 'strex' success?
bne 1f
movs r0, #0 @ it also update EQ flag
1: it ne
movne r0, #-1
bx lr
1: beq 2f
mov r0, #-1
2: bx lr
ENDPROC(pthread_mutex_trylock)

@ int pthread_mutex_unlock(pthread_mutex_t *mutex)
Expand All @@ -54,8 +54,8 @@ ENTRY(pthread_mutex_unlock)
bne 0b
dmb @ ARMv7-M ARM, A3.4.6
movs r0, #0 @ it also update EQ flag
1: itt ne
movne r1, #SYS_PTHREAD_MUTEX_UNLOCK
svcne #1
bx lr
ENDPROC(pthread_mutex_unlock)
1: beq 2f
mov r1, #SYS_PTHREAD_MUTEX_UNLOCK
svc #1
2: bx lr
ENDPROC(pthread_mutex_lock)
10 changes: 10 additions & 0 deletions mk/flags.mk
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ CFLAGS += \
CFLAGS += \
-D CONFIG_KERNEL_STACK_CHECKING

# Scheduler
ifdef SCHED
CFLAGS += -D SCHED_CLASS=SCHED_CLASS_$(SCHED)
RESCHED:
$(VECHO) " RM\t\tkernel/main.o\n"
$(Q)$(RM) kernel/main.o

FORCE: RESCHED
endif

LDFLAGS += \
-nostartfiles -specs=nano.specs \
-Wl,-Map=$(NAME).map -Wl,-Tpiko.lds -Wl,--gc-sections
Expand Down