User-state implementation of thread scheduling (task scheduling)

Source: Internet
Author: User

The code applies to the X86_64 schema.

Preemption is not supported and the task can only make its own CPU.

Here is the code, which copies all of the code into a. c file and compiles the run.


/*
* This software is free, open source software.
* The copyright of the software (including the source code and the binary release version) is owned by the public.
* You are free to use and distribute the software.
* You may also use the software (including source code and binary release versions) in any form or for any purpose, without any copyright restrictions.
* =====================
* Author: Sun Mingpao
* Email: [Email protected]
*/


#include <stdio.h>
#include <string.h>


#define MAX_TASK_NUM (10)
#define TASK_STACK_SIZE (4096)


#define Dbg_print (FMT, args ...) \
Do \
{ \
printf ("dbg:%s (%d)-%s:\n" FMT "\ n", __file__,__line__,__function__,# #args); \
} while (0)


typedef void * (*TASK_ENTRY_PTR) (void *);
typedef struct
{
Char name[64];
unsigned long state;
TASK_ENTRY_PTR entry;
unsigned long ret;
unsigned long SP;
unsigned long pc;
unsigned long stack[task_stack_size/sizeof (unsigned long)];
} __attribute__ ((packed)) T_task;


#define STATE_INVALID (0)
#define STATE_SLEEPING (1)
#define STATE_RUNNING (2)
#define STATE_FINISHED (3)


T_task G_at_tasks[max_task_num];
int g_task_cnt = 0;


unsigned long process_main_thread_sp;
T_task *pt_cur_running_task;
unsigned long prev_task_sp, prev_task_pc;
unsigned long next_task_sp, next_task_pc;
#define SAVE_MAIN_THREAD_CONTEXT () \
do { \
ASM volatile ("pushfq\n\t"/* Save Flags */ \
"Pushq%%rax\n\t" \
"Pushq%%rdi\n\t" \
"Pushq%%rsi\n\t" \
"Pushq%%rdx\n\t" \
"Pushq%%rcx\n\t" \
"Pushq%%rbx\n\t" \
"Pushq%%rbp\n\t" \
"Movq%%rsp,%[main_thread_sp]\n\t" \
: [main_thread_sp] "=m" (PROCESS_MAIN_THREAD_SP) \
); \
} while (0)


#define RESTORE_MAIN_THREAD_CONTEXT () \
do { \
ASM volatile ("Movq%[main_thread_sp],%%rsp\n\t" \
"Popq%%rbp\n\t" \
"Popq%%rbx\n\t" \
"Popq%%rcx\n\t" \
"Popq%%rdx\n\t" \
"Popq%%rsi\n\t" \
"Popq%%rdi\n\t" \
"Popq%%rax\n\t" \
"Popfq\n\t" \
:: [main_thread_sp] "M" (PROCESS_MAIN_THREAD_SP) \
); \
} while (0)


int i;
int Task_scheduler ()
{
unsigned long ret;
ASM volatile ("Movq%%rax,%[task_ret]\n\t"
: [Task_ret] "=m" (ret)
);


if (Pt_cur_running_task)
{
pt_cur_running_task->state=state_finished;
pt_cur_running_task->ret=ret;
Dbg_print ("Task%s exit with code%lu", Pt_cur_running_task->name, Pt_cur_running_task->ret);
}

Restore_main_thread_context ();


for (i=0;i<max_task_num;i++)
{
Pt_cur_running_task = & (G_at_tasks[i]);
if (pt_cur_running_task->state==state_sleeping)
{
pt_cur_running_task->state=state_running;
NEXT_TASK_SP = pt_cur_running_task->sp;
NEXT_TASK_PC = pt_cur_running_task->pc;


/* Prepare to run the next running task */
Save_main_thread_context ();
ASM volatile ("Movq%[next_sp],%%rsp\n\t"
/* "Movq $0x0,%%rdi\n\t"
"Pushq task_return\n\t" * *
"Popq%%rbp\n\t" \
"Popq%%rbx\n\t" \
"Popq%%rcx\n\t" \
"Popq%%rdx\n\t" \
"Popq%%rsi\n\t" \
"Popq%%rdi\n\t" \
"Popq%%rax\n\t" \
"Popfq\n\t" \
"JMP *%[next_pc]\n\t"
:: [next_sp] "M" (next_task_sp), [next_pc] "M" (NEXT_TASK_PC)
);




}
}


Dbg_print ("==no task to run. So we exit ");
return 0;
}


#define PUSH_TASK_STACK (SP, data) \
Do \
{ \
sp--; \
*SP = data; \
} while (0)


int create_task (const char *name, void *task_entry, void *para)
{
unsigned long *sp;
T_task *pt_task = & (g_at_tasks[g_task_cnt]);
strncpy (pt_task->name, name, sizeof (Pt_task->name));
Pt_task->entry = Task_entry;
PT_TASK-&GT;SP = (unsigned long) ((void *) (Pt_task + 1));
Pt_task->state = state_sleeping;
SP = (void *) (PT_TASK-&GT;SP);
Push_task_stack (SP, (unsigned long) (void *) &task_scheduler);
PT_TASK-&GT;PC = (unsigned long) task_entry;
Push_task_stack (sp, 0);
Push_task_stack (sp, 0);
Push_task_stack (SP, (unsigned long) para);
Push_task_stack (sp, 0);
Push_task_stack (sp, 0);
Push_task_stack (sp, 0);
Push_task_stack (sp, 0);
Push_task_stack (sp, PT_TASK-&GT;SP); /* Push BP at last */
PT_TASK-&GT;SP = (unsigned long) (void *) SP;



g_task_cnt++;


return 0;
}




#define SWITCH_TO (prev, next) \
do { \
ASM volatile ("pushfq\n\t" \
"Pushq%%rax\n\t" \
"Pushq%%rdi\n\t" \
"Pushq%%rsi\n\t" \
"Pushq%%rdx\n\t" \
"Pushq%%rcx\n\t" \
"Pushq%%rbx\n\t" \
"Pushq%%rbp\n\t" \
"Movq%%rsp,%[prev_sp]\n\t" \
"Movq $1f,%[prev_pc]\n\t" \
"Movq%[next_sp],%%rsp\n\t" \
"Popq%%rbp\n\t"/* Restore EBP */ \
"Popq%%rbx\n\t" \
"Popq%%rcx\n\t" \
"Popq%%rdx\n\t" \
"Popq%%rsi\n\t" \
"Popq%%rdi\n\t" \
"Popq%%rax\n\t" \
"Popfq\n\t" \
"JMP *%[next_pc]\n\t" \
"1:\t"\
"Nop\n\t" \
: [prev_sp] "=m" (PREV-&GT;SP), \
[PREV_PC] "=m" (PREV-&GT;PC) \
: [next_sp] "M" (next_task_sp), [next_pc] "M" (NEXT_TASK_PC) \
); \
}while (0)


void Schedule ()
{
T_task *prev=pt_cur_running_task, *next=null;
for (i=0;i<max_task_num;i++)
{
Next = & (G_at_tasks[i]);
if (next->state==state_sleeping)
{
pt_cur_running_task->state=state_sleeping;
PREV_TASK_SP = pt_cur_running_task->sp;
PREV_TASK_PC = pt_cur_running_task->pc;


Pt_cur_running_task = Next;
pt_cur_running_task->state=state_running;
NEXT_TASK_SP = pt_cur_running_task->sp;
NEXT_TASK_PC = pt_cur_running_task->pc;


Break
}
}


if (i==max_task_num) return;


Switch_to (prev, next);
}


int start_sched ()
{
/* Prepare to run the initial task Father_of_all_task--g_at_tasks[0] */
Save_main_thread_context ();
Task_scheduler ();
return 0;
}


/* Above is the implementation of the scheduling function, the following is the use of the example */


void * Usr_task1 (void *para)
{
int i;
Dbg_print ("==enter");
for (i=0; i<3; i++)
{
Dbg_print ("==%d", I);
Schedule ();
}
Dbg_print ("==exit");
return (void *) 100UL;
}


void * Usr_task2 (void *para)
{
int i;
Dbg_print ("==enter");
for (i=0; i<3; i++)
{
Dbg_print ("==%d", I);
Schedule ();
}
Dbg_print ("==exit");
return (void *) 200UL;
}


void * Father_of_all_task (void *para)
{
Dbg_print ("==enter");
Create_task ("Usr_task1", Usr_task1, NULL);
Create_task ("Usr_task2", Usr_task2, NULL);
Dbg_print ("==exit");
return (void *) 2015UL;
}


int main (int argc, char *argv[])
{
Dbg_print ("Hello");
Create_task ("Father_of_all_task", Father_of_all_task, NULL);
Start_sched ();
Dbg_print ("Good Bye");
return 0;
}


User-state implementation of thread scheduling (task scheduling)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.