以åã«ç¿»èš³ãããRESTã«é¢ããæçš¿ã«æ³šç®ããŠããã ãããããšãããããŸããä»æ¥ã¯ãã·ã¹ãã èšèšã®ãããã¯ãå°ãç°ãªãè§åºŠããèŠãŠãLinuxã®èå人ã§ããStephen Brennanã«ããèšäºã®ç¿»èš³ãå ¬éããããšãææ¡ããŸãã圌ã¯ããŠãŒã¶ãŒã¹ããŒã¹ã§ã®ãã«ãã¿ã¹ã¯ã®ç¬èªã®å®è£ ãšãã®æçšæ§ã«ã€ããŠèª¬æããŠããŸãã
ãã«ãã¿ã¹ã¯ã¯ããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã«ãã£ãŠæäŸãããä»ã®å€ãã®æ©èœãšåæ§ã«ãåœç¶ã®ããšãšèŠãªãã ãã§ãªããéåžžã®ãã®ãšããŠèªèããŸããç§ãã¡ã®åŒ·åãªã³ã³ãã¥ãŒã¿ãŒãšã¹ããŒããã©ã³ã§ã¯ãã³ã³ãã¥ãŒã¿ãŒãäœçŸãã®ããã»ã¹ãåŠçã§ããªããšããèãã¯å¥åŠã«æããŸãããããã³ã³ãã¥ãŒã¿ããšãŠã䟿å©ã«ããå¯èœæ§ã®1ã€ã ãšæããŸããããããåå ã§ã³ã³ãã¥ãŒã¿ã¯éåžžã«è€éã«ãªããéæ³ã®ããã«èŠããããšããããŸãã
ãã«ãã¿ã¹ã¯ãå®è£ ããã³ãŒãã«æãåºãããšã¯å°é£ã§ãããã©ã®å Žåã«èªåã§å®è£ ããæ¹ãããããåžžã«æ確ã§ãããšã¯éããªãããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã å šäœãäœæããå¿ èŠã¯ãããŸãããèªåã§æ°ä»ããŸã§ã¯ããã®çŸè±¡ãå®å šã«ç解ããããšã¯äžå¯èœã ãšç¢ºä¿¡ããŠããŸãããã®ãããç°¡åãªã¹ã¬ããã®å®è£ ã§ã©ã®ããã«éã¶ããšãã§ãããã説æããèšäºãæžãããšã«ããŸããããã®èšäºã§ã¯ã
ïŒãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã§ã¯ãªãïŒéåžžã®Cããã°ã©ã ã«åçŽãªã¹ããªãŒã ãå®è£ ããŸãã
setjmpãšlongjmpã«ã€ããŠã®åæ çãªéžè±
ã¹ã±ãžã¥ãŒã©ãŒã¯ãé¢æ°
setjmp()
ãšã«å€§ããäŸåããŸãlongjmp()
ããããã¯å°ãéæ³ã®ããã«èŠããã®ã§ãæåã«ããããäœãããã®ãã説æãã次ã«å°ãæéããããŠæ£ç¢ºãªæ¹æ³ã説æããŸãã
ãã®é¢æ°ã
setjmp()
䜿çšãããšãããã°ã©ã ãå®è¡ã®ã©ã®æ®µéã«ãã£ããã«é¢ããæ
å ±ãèšé²ã§ããããããã®ãã€ã³ãã«åã³ãžã£ã³ãã§ããŸããåå€æ°ãæž¡ããjmp_buf
ããã®æ
å ±ãæ ŒçŽãããŸããåããŠæ»ã£ããšããé¢æ°setjmp()
ã¯0ãè¿ããŸãã
åŸã§ãé¢æ°
longjmp(jmp_buf, value)
ã䜿çšããŠãåŒã³åºããããã€ã³ãããå³åº§ã«å®è¡ãåéã§ããŸãsetjmp()
ãããªãã®ããã°ã©ã ã§ã¯ããã®ç¶æ³ã¯setjmp()
2床ç®ã«æ»ã£ãããã«èŠããŸããä»åã¯åŒæ°ãè¿ãããŸãvalue
åæ Œããããš-2longjmp()
çªç®ã®ãªã¿ãŒã³ãšæåã®ãªã¿ãŒã³ãåºå¥ããæ¹ã䟿å©ã§ãããã®ç¹ã説æããäŸã次ã«ç€ºããŸãã
#include <stdio.h>
#include <setjmp.h>
jmp_buf saved_location;
int main(int argc, char **argv)
{
if (setjmp(saved_location) == 0) {
printf("We have successfully set up our jump buffer!\n");
} else {
printf("We jumped!\n");
return 0;
}
printf("Getting ready to jump!\n");
longjmp(saved_location, 1);
printf("This will never execute...\n");
return 0;
}
ãã®ããã°ã©ã ãã³ã³ãã€ã«ããŠå®è¡ãããšã次ã®åºåãåŸãããŸãã
We have successfully set up our jump buffer!
Getting ready to jump!
We jumped!
ãããŒïŒããã¯gotoã¹ããŒãã¡ã³ããšåãã§ããããã®å Žåãé¢æ°ã®å€ã«ãžã£ã³ãããããã«äœ¿çšããããšãã§ããŸãããŸã
goto
ãéåžžã®é¢æ°åŒã³åºãã®ããã«èŠãããããèªã¿ã«ããã§ããããªãã®ã³ãŒãã䜿çšããŠããå Žåsetjmp()
ãšè±å¯ã§longjmp()
ãïŒããªããå«ãïŒã誰ã®ããã«ãããèªã¿åãããšãéåžžã«å°é£ã«ãªããŸãã
ã®å Žåãšåæ§ã«
goto
ãäžè¬çã«ã¯ãšãé¿ããããšsetjmp()
ããå§ããlongjmp()
ãŸãããããã®ããã«goto
ãäžèšã®é¢æ°ã¯ãæ§ãããã€äžè²«ããŠäœ¿çšãããšäŸ¿å©ã§ããã¹ã±ãžã¥ãŒã©ãŒã¯ã³ã³ããã¹ããåãæ¿ããããšãã§ããå¿
èŠãããããããããã®æ©èœã責任ãæã£ãŠäœ¿çšããŸããæãéèŠãªããšã¯ããã©ã³ããŒãŠãŒã¶ãŒããã®çš®ã®è€éãã«å¯ŸåŠããå¿
èŠããªãããã«ãAPIãããããã®é¢æ°ã䜿çšããããšã§ãã
Setjmpãšlongjmpã¯ã¹ã¿ãã¯ãä¿åããŸãã
Trueãé¢æ°
setjmp()
ãlongjmp()
ãããªãçš®é¡ã®ãããã³ã°ããµããŒãããããšãç®çãšããŠããŸããããããã¯éåžžã«ç¹æ®ãªå®çšçãªã±ãŒã¹ã®ããã«èšèšãããŸãããHTTPãªã¯ãšã¹ãã®äœæãªã©ãè€éãªæäœãå®è¡ããŠãããšæ³åããŠãã ããããã®å Žåãè€éãªäžé£ã®é¢æ°åŒã³åºããå«ãŸãããããã®ããããã倱æããå Žåã¯ãããããããç¹å¥ãªãšã©ãŒã³ãŒããè¿ãå¿
èŠããããŸãããã®ãããªã³ãŒãã¯ãé¢æ°ãåŒã³åºãå ŽæïŒããããæ°ååïŒã§ã次ã®ãªã¹ãã®ããã«ãªããŸãã
int rv = do_function_call();
if (rv != SUCCESS) {
return rv;
}
ãã®æå³
setjmp()
ãšlongjmp()
ã¯setjmp()
ãæ¬åœã«é£ããä»äºã«çæããåã«å Žæãè³ããã®ã«åœ¹ç«ã€ãã®ã§ãã次ã«ããã¹ãŠã®ãšã©ãŒåŠçã1ãæã«äžå
åã§ããŸãã
int rv;
jmp_buf buf;
if ((rv = setjmp(buf)) != 0) {
/* */
return;
}
do_complicated_task(buf, args...);
é¢ä¿ããæ©èœã®ããããã倱æããå Žå
do_complicated_task()
ãããã¯ãã èµ·ããlongjmp(buf, error_code)
ãŸããããã¯ãã³ã³ããžã·ã§ã³å
ã®åé¢æ°do_complicated_task()
ãä»»æã®é¢æ°åŒã³åºããæåãããšæ³å®ã§ããããšãæå³ããŸããã€ãŸããåé¢æ°åŒã³åºãã®ãšã©ãŒãåŠçããããã«ãã®ã³ãŒããé
眮ããããšã¯ã§ããŸããïŒå®éã«ã¯ãããã¯ã»ãšãã©å®è¡ãããŸããããããã¯å¥ã®èšäºã®ãããã¯ã§ãïŒ ..ã
ããã§ã®åºæ¬çãªèãæ¹ã¯
longjmp()
ãæ·±ããã¹ããããé¢æ°ããã®ã¿ãžã£ã³ãã§ãããšããããšã§ãã以åã«ãžã£ã³ããããæ·±ããã¹ããããé¢æ°ã«ãžã£ã³ãããããšã¯ã§ããŸãããããã¯ãé¢æ°ãããžã£ã³ããããšãã®ã¹ã¿ãã¯ã®å€èŠ³ã§ããã¢ã¹ã¿ãªã¹ã¯ïŒ*ïŒã¯ããããæ ŒçŽãããŠããã¹ã¿ãã¯ãã€ã³ã¿ãæå³ããŸãsetjmp()
ã
| Stack before longjmp | Stack after longjmp
+-------------------------+----------------------------
stack | main() (*) | main()
grows | do_http_request() |
down | send_a_header() |
| | write_bytes() |
v | write() - fails! |
ã芧ã®ãšãããã¹ã¿ãã¯ãåŸæ¹ã«ç§»åããããšããã§ããªããããããŒã¿ãç Žæããå±éºã¯ãããŸãããäžæ¹ãã¿ã¹ã¯éããžã£ã³ããããå Žåã¯ã©ããªããæ³åããŠã¿ãŠãã ãããé»è©±ããã
setjmp()
ãŠããæ»ã£ãŠããŠãä»ã®ããšãããŠã以åã«è¡ã£ãŠããäœæ¥ãåéããããšãããšãåé¡ãçºçããŸãã
| Stack at setjmp() | Stack later | Stack after longjmp()
+-------------------+------------------+----------------------
stack | main() | main() | main()
grows | do_task_one() | do_task_two() | do_stack_two()
down | subtask() | subtask() | subtask()
| | foo() | | ???
v | bar() (*) | (*) | ??? (*)
ä¿å
setjmp()
ãããã¹ã¿ãã¯ãã€ã³ã¿ã¯ãååšããªããªã£ãã¹ã¿ãã¯ãã¬ãŒã ãæããããæç¹ã§ä»ã®ããŒã¿ã«ãã£ãŠäžæžããããå¯èœæ§ããããŸããå©ããåãlongjmp()
ãŠæ»ã£ãŠããé¢æ°ã«æ»ãããšãããšãéåžžã«å¥åŠãªããšãå§ãŸããããã°ã©ã å
šäœã厩å£ããå¯èœæ§ããããŸãã
é埳ïŒãããã®ãããªè€éãªã¿ã¹ã¯ã䜿çš
setjmp()
ãlongjmp()
ãŠãžã£ã³ãããå Žåã¯ãåã¿ã¹ã¯ã«ç¬èªã®åå¥ã®ã¹ã¿ãã¯ãããããšã確èªããå¿
èŠããããŸãããã®å Žåãlongjmp()
ã¹ã¿ãã¯ãã€ã³ã¿ããªã»ããããããšãããã°ã©ã èªäœãã¹ã¿ãã¯ãç®çã®ã¹ã¿ãã¯ã«çœ®ãæããã¹ã¿ãã¯ã®æ¶å»ãçºçããªããããåé¡ã¯å®å
šã«è§£æ¶ãããŸãã
ã¹ã±ãžã¥ãŒã©APIãæžããŠã¿ãŸããã
éžè±ã¯å°ãé·ãã§ãããç§ãã¡ãåŠãã ããšãæŠåšã«ããŠãŒã¶ãŒã¹ããŒã¹ãããŒãå®è£ ã§ããããã«ãªããŸããããŸããã¹ã¬ããã®åæåãäœæãéå§ã®ããã«APIãèªåã§èšèšããããšã¯éåžžã«äŸ¿å©ã§ããããšã«æ³šæããŠãã ãããäºåã«ãããè¡ããšãäœãæ§ç¯ããããšããŠããã®ããããããç解ã§ããããã«ãªããŸãã
void scheduler_init(void);
void scheduler_create_task(void (*func)(void*), void *arg);
void scheduler_run(void);
ãããã®é¢æ°ã¯ãã¹ã±ãžã¥ãŒã©ãŒãåæåããã¿ã¹ã¯ãè¿œå ããæåŸã«ã¹ã±ãžã¥ãŒã©ãŒã§ã¿ã¹ã¯ãéå§ããããã«äœ¿çšãããŸããèµ·åãããšã
scheduler_run()
ãã¹ãŠã®ã¿ã¹ã¯ãå®äºãããŸã§å®è¡ãããŸããçŸåšå®è¡äžã®ã¿ã¹ã¯ã«ã¯ã次ã®APIããããŸãã
void scheduler_exit_current_task(void);
void scheduler_relinquish(void);
æåã®é¢æ°ã¯ãã¿ã¹ã¯ãçµäºãã圹å²ãæãããŸããã¿ã¹ã¯ãçµäºããããšããã®æ©èœããæ»ããšãã«å¯èœã§ããããããã®æ§é ã¯äŸ¿å®äžååšããã ãã§ãã 2çªç®ã®é¢æ°ã¯ãå¥ã®ã¿ã¹ã¯ããã°ããå®è¡ããå¿ èŠãããããšãã¹ã¬ãããã¹ã±ãžã¥ãŒã©ãŒã«éç¥ããæ¹æ³ã説æããŸããã¿ã¹ã¯ããåŒã³åºããš
scheduler_relinquish()
ãä»ã®ã¿ã¹ã¯ã®å®è¡äžã«äžæçã«äžæã§ããŸããããããæçµçã«ã¯é¢æ°ãæ»ããæåã®ã¿ã¹ã¯ãç¶è¡ã§ããŸãã
å ·äœçãªäŸãšããŠãAPIã®æ¶ç©ºã®äœ¿çšäŸãèããŠã¿ãŸããããããã䜿çšããŠã¹ã±ãžã¥ãŒã©ããã¹ãããŸãã
#include <stdlib.h>
#include <stdio.h>
#include "scheduler.h"
struct tester_args {
char *name;
int iters;
};
void tester(void *arg)
{
int i;
struct tester_args *ta = (struct tester_args *)arg;
for (i = 0; i < ta->iters; i++) {
printf("task %s: %d\n", ta->name, i);
scheduler_relinquish();
}
free(ta);
}
void create_test_task(char *name, int iters)
{
struct tester_args *ta = malloc(sizeof(*ta));
ta->name = name;
ta->iters = iters;
scheduler_create_task(tester, ta);
}
int main(int argc, char **argv)
{
scheduler_init();
create_test_task("first", 5);
create_test_task("second", 2);
scheduler_run();
printf("Finished running all tasks!\n");
return EXIT_SUCCESS;
}
ãã®äŸã§ã¯ãåãæ©èœãå®è¡ãããç°ãªãåŒæ°ãåã2ã€ã®ã¿ã¹ã¯ãäœæããŸãããããã£ãŠããããã®å®è£ ã¯åå¥ã«è¿œè·¡ã§ããŸããåã¿ã¹ã¯ã¯ãèšå®ãããåæ°ã®å埩ãå®è¡ããŸããåå埩ã§ãã¡ãã»ãŒãžãåºåããŠãããå¥ã®ã¿ã¹ã¯ãå®è¡ããŸããããã°ã©ã ã®åºåã®ãããªãã®ã衚瀺ãããããšãæåŸ ããŠããŸãã
task first: 0
task second: 0
task first: 1
task second: 1
task first: 2
task first: 3
task first: 4
Finished running all tasks!
ã¹ã±ãžã¥ãŒã©APIãå®è£ ããŸããã
APIãå®è£ ããã«ã¯ãã¿ã¹ã¯ã®ããçš®ã®å éšè¡šçŸãå¿ èŠã§ããããã§ã¯ãããžãã¹ã«åãæãããŸããããå¿ èŠãªãã£ãŒã«ããéããŸãããïŒ
struct task {
enum {
ST_CREATED,
ST_RUNNING,
ST_WAITING,
} status;
int id;
jmp_buf buf;
void (*func)(void*);
void *arg;
struct sc_list_head task_list;
void *stack_bottom;
void *stack_top;
int stack_size;
};
ãããã®åãã£ãŒã«ãã«ã€ããŠåå¥ã«èª¬æããŸããããäœæããããã¹ãŠã®ã¿ã¹ã¯ã¯ãå®è¡åã«ãäœææžã¿ãç¶æ ã§ããå¿ èŠããããŸããã¿ã¹ã¯ã®å®è¡ãéå§ããããšãã¿ã¹ã¯ã¯ãå®è¡äžãç¶æ ã«ãªããã¿ã¹ã¯ãäœããã®éåææäœãåŸ æ©ããå¿ èŠãããå Žåã¯ããåŸ æ©äžãç¶æ ã«ããããšãã§ããŸãããã£ãŒã«ã
id
ã¯ãåã«ã¿ã¹ã¯ã®äžæã®èå¥åã§ããããã«buf
ã¯ãlongjmp()
ã¿ã¹ã¯ããã€å®è¡ããŠåéãããã«é¢ããæ
å ±ãå«ãŸããŠããŸããfunc
ããã³ãã£ãŒã«ãarg
ã¯ã«æž¡ããscheduler_create_task()
ãã¿ã¹ã¯ãéå§ããããã«å¿
èŠã§ãããã®ãã£ãŒã«ãã¯task_list
ããã¹ãŠã®ã¿ã¹ã¯ã®äºéã«ãªã³ã¯ããããªã¹ããå®è£
ããããã«å¿
èŠã§ãããã£ãŒã«ãstack_bottom
ãstack_top
ããã³stack_size
ãã¹ãŠã¯ããã®ã¿ã¹ã¯å°çšã®åå¥ã®ã¹ã¿ãã¯ã«å±ããŠããŸããäžã¯ã«ãã£ãŠè¿ãããã¢ãã¬ã¹ã§ãmalloc()
ãã ãããtopãã¯ãã¡ã¢ãªå
ã®æå®ãããé åã®ããäžã®ã¢ãã¬ã¹ãžã®ãã€ã³ã¿ã§ããx86ã¹ã¿ãã¯ã¯äžã«åãã£ãŠå€§ãããªããããã¹ã¿ãã¯ãã€ã³ã¿ãstack_top
ã§ã¯ãªãå€ã«èšå®ããå¿
èŠããããŸãstack_bottom
ã
ãã®ãããªç¶æ³ã§ã¯ã次ã®é¢æ°ãå®è£ ã§ããŸã
scheduler_create_task()
ã
void scheduler_create_task(void (*func)(void *), void *arg)
{
static int id = 1;
struct task *task = malloc(sizeof(*task));
task->status = ST_CREATED;
task->func = func;
task->arg = arg;
task->id = id++;
task->stack_size = 16 * 1024;
task->stack_bottom = malloc(task->stack_size);
task->stack_top = task->stack_bottom + task->stack_size;
sc_list_insert_end(&priv.task_list, &task->task_list);
}
ã䜿çš
static int
ãããšãé¢æ°ãåŒã³åºããããã³ã«idãã£ãŒã«ããã€ã³ã¯ãªã¡ã³ããããããã«æ°ããçªå·ã衚瀺ãããããšãä¿èšŒãããŸããsc_list_insert_end()
åã«struct task
ã°ããŒãã«ãªã¹ãã«è¿œå ããæ©èœãé€ããŠãä»ã®ãã¹ãŠã¯èª¬æãªãã§æ確ã§ãªããã°ãªããŸãããã°ããŒãã«ãªã¹ãã¯ãã¹ã±ãžã¥ãŒã©ã®ãã¹ãŠã®ãã©ã€ããŒãããŒã¿ãå«ã2çªç®ã®æ§é å
ã«æ ŒçŽãããŸãã以äžã¯ãæ§é èªäœãšãã®åæåé¢æ°ã§ãã
struct scheduler_private {
jmp_buf buf;
struct task *current;
struct sc_list_head task_list;
} priv;
void scheduler_init(void)
{
priv.current = NULL;
sc_list_init(&priv.task_list);
}
ãã®ãã£ãŒã«ãã¯
task_list
ãã¿ã¹ã¯ãªã¹ããåç
§ããããã«äœ¿çšãããŸãïŒåœç¶ã®ããšãªããïŒããã®ãã£ãŒã«ãã«current
ã¯ãçŸåšå®è¡ãããŠããã¿ã¹ã¯ãæ ŒçŽãããŸãïŒãŸãã¯null
ãçŸæç¹ã§ãã®ãããªã¿ã¹ã¯ããªãå ŽåïŒãæãéèŠãªã®ã¯ããã£ãŒã«ãbuf
ãã³ãŒãã«ãžã£ã³ãããããã«äœ¿çšãããããšã§ãscheduler_run()
ã
enum {
INIT=0,
SCHEDULE,
EXIT_TASK,
};
void scheduler_run(void)
{
/* ! */
switch (setjmp(priv.buf)) {
case EXIT_TASK:
scheduler_free_current_task();
case INIT:
case SCHEDULE:
schedule();
/* , */
return;
default:
fprintf(stderr, "Uh oh, scheduler error\n");
return;
}
}
é¢æ°ãåŒã³åºããããšããã«ããã€ã§ããã®é¢æ°ã«æ»ãããšãã§ãããã
scheduler_run()
ã«ãããã¡ãŒãèšå®setjmp()
ããŸããååã¯0ïŒINITïŒãè¿ãããããã«åŒã³åºããŸãschedule()
ããã®åŸãSCHEDULEãŸãã¯EXIT_TASKå®æ°ãã«æž¡ãããšãã§ãlongjmp()
ãŸããããã«ãããããŸããŸãªåäœãåŒãèµ·ããããŸããä»ã®ãšãããEXIT_TASKã®ã±ãŒã¹ãç¡èŠããŠãå®è£
ã«çŽæ¥ãžã£ã³ãããŸãããschedule()
ã
static void schedule(void)
{
struct task *next = scheduler_choose_task();
if (!next) {
return;
}
priv.current = next;
if (next->status == ST_CREATED) {
/*
* .
* , .
*/
register void *top = next->stack_top;
asm volatile(
"mov %[rs], %%rsp \n"
: [ rs ] "+r" (top) ::
);
/*
*
*/
next->status = ST_RUNNING;
next->func(next->arg);
/*
* , . â ,
*
*/
scheduler_exit_current_task();
} else {
longjmp(next->buf, 1);
}
/* */
}
ãŸããå éšé¢æ°ãåŒã³åºããŠã次ã«å®è¡ããã¿ã¹ã¯ãéžæããŸãããã®ã¹ã±ãžã¥ãŒã©ãŒã¯éåžžã®ã«ã«ãŒã»ã«ã®ããã«æ©èœããããããªã¹ãããæ°ããã¿ã¹ã¯ãéžæããã ãã§ãããã®é¢æ°ãNULLãè¿ãå Žåãå®è¡ããã¿ã¹ã¯ã¯ãã以äžãªãã®ã§ãæ»ããŸãããã以å€ã®å Žåã¯ãã¿ã¹ã¯ã®å®è¡ãéå§ãããïŒST_CREATEDç¶æ ã®å ŽåïŒãå®è¡ãåéããå¿ èŠããããŸãã
äœæããã¿ã¹ã¯ãå®è¡ããã«ã¯ãx86_64ã®ã¢ã»ã³ããªåœä»€ã䜿çšããŠããã£ãŒã«ãã
stack_top
ã¬ãžã¹ã¿rsp
ïŒã¹ã¿ãã¯ãã€ã³ã¿ïŒã«å²ãåœãŠãŸãã次ã«ãã¿ã¹ã¯ã®ç¶æ
ãå€æŽããé¢æ°ãå®è¡ããŠçµäºããŸãã泚ïŒã¹ã¿ãã¯ãã€ã³ã¿ãŒã®ä¿åãšåé
眮ã®setjmp()
äž¡æ¹ãããlongjmp()
ãããããã§ã¯ãã¢ã»ã³ãã©ãŒã䜿çšããŠã¹ã¿ãã¯ãã€ã³ã¿ãŒãå€æŽããã ãã§æžã¿ãŸãã
ã¿ã¹ã¯ããã§ã«éå§ãããŠããå Žåããã£ãŒã«ãã«ã¯ã¿ã¹ã¯ãåé
buf
ããlongjmp()
ããã«å¿
èŠãªã³ã³ããã¹ããå«ãŸããŠããå¿
èŠãããããããããå®è¡ããŸãã
次ã«ã次ã«å®è¡ããã¿ã¹ã¯ãéžæãããã«ããŒé¢æ°ãèŠãŠã¿ãŸãããããããã¹ã±ãžã¥ãŒã©ãŒã®å¿èéšã§ãããåã«è¿°ã¹ãããã«ããã®ã¹ã±ãžã¥ãŒã©ãŒã¯ã«ã«ãŒã»ã«ã®ããã«æ©èœããŸãã
static struct task *scheduler_choose_task(void)
{
struct task *task;
sc_list_for_each_entry(task, &priv.task_list, task_list, struct task)
{
if (task->status == ST_RUNNING || task->status == ST_CREATED) {
sc_list_remove(&task->task_list);
sc_list_insert_end(&priv.task_list, &task->task_list);
return task;
}
}
return NULL;
}
ãªã³ã¯ãªã¹ãã®å®è£ ïŒLinuxã«ãŒãã«ããååŸïŒã«ç²ŸéããŠããªãå Žåã¯ã倧ããããšã¯ãããŸãããé¢æ°
sc_list_for_each_entry()
ã¯ãã¿ã¹ã¯ãªã¹ãå
ã®ãã¹ãŠã®ã¿ã¹ã¯ãå埩åŠçã§ããããã«ãããã¯ãã§ããæåã«éžæå¯èœãªã¿ã¹ã¯ïŒä¿çç¶æ
ã§ã¯ãªãïŒãçŸåšã®äœçœ®ããåé€ãããã¿ã¹ã¯ãªã¹ãã®æåŸã«ç§»åããŸããããã«ããã次ã«ã¹ã±ãžã¥ãŒã©ãå®è¡ãããšãã«ãå¥ã®ã¿ã¹ã¯ãåãåãããšãä¿èšŒãããŸãïŒã¿ã¹ã¯ãããå ŽåïŒãéžæå¯èœãªæåã®ã¿ã¹ã¯ãè¿ããŸããã¿ã¹ã¯ããŸã£ãããªãå Žåã¯NULLãè¿ããŸãã
æåŸã«ãå®è£
scheduler_relinquish()
ã«ç§»ã£ãŠãã¿ã¹ã¯ãã©ã®ããã«èªå·±æé€ã§ããããèŠãŠã¿ãŸãããã
void scheduler_relinquish(void)
{
if (setjmp(priv.current->buf)) {
return;
} else {
longjmp(priv.buf, SCHEDULE);
}
}
ããã¯
setjmp()
ãã¹ã±ãžã¥ãŒã©ãŒã®é¢æ°ã®ãã1ã€ã®äœ¿çšäŸã§ããåºæ¬çã«ããã®ãªãã·ã§ã³ã¯å°ãæ··ä¹±ããŠããããã«èŠãããããããŸãããã¿ã¹ã¯ããã®é¢æ°ãåŒã³åºããšããããã䜿çšãsetjmp()
ãŠçŸåšã®ã³ã³ããã¹ãïŒå®éã®ã¹ã¿ãã¯ãã€ã³ã¿ãŒãå«ãïŒãä¿åããŸãã次ã«ãããã䜿çšlongjmp()
ããŠã¹ã±ãžã¥ãŒã©ãŒã«å
¥ãïŒããã§ãscheduler_run()
ïŒãSCHEDULEé¢æ°ãæž¡ããŸãããããã£ãŠãæ°ããã¿ã¹ã¯ãå²ãåœãŠãããã«ãé¡ãããŸãã
ã¿ã¹ã¯ãåéããããšãé¢æ°
setjmp()
ã¯ãŒã以å€ã®å€ã§æ»ãã以åã«å®è¡ããŠããå¯èœæ§ã®ããã¿ã¹ã¯ããã¹ãŠçµäºããŸãã
æåŸã«ãã¿ã¹ã¯ãçµäºãããšã©ããªããŸããïŒããã¯ãæ瀺çã«ãexité¢æ°ãåŒã³åºããã察å¿ããã¿ã¹ã¯é¢æ°ããæ»ãããšã«ãã£ãŠè¡ãããŸãïŒã
void scheduler_exit_current_task(void)
{
struct task *task = priv.current;
sc_list_remove(&task->task_list);
longjmp(priv.buf, EXIT_TASK);
/* */
}
static void scheduler_free_current_task(void)
{
struct task *task = priv.current;
priv.current = NULL;
free(task->stack_bottom);
free(task);
}
ããã¯2ã€ã®éšåãããªãããã»ã¹ã§ããæåã®é¢æ°ã¯ãã¿ã¹ã¯èªäœã«ãã£ãŠçŽæ¥è¿ãããŸããããã«å¯Ÿå¿ãããšã³ããªã¯å²ãåœãŠãããªããªããããã¿ã¹ã¯ã®ãªã¹ãããåé€ããŸãã次ã«ãã䜿çš
longjmp()
ããŠãé¢æ°ã«æ»ããŸãscheduler_run()
ãä»åã¯EXIT_TASKã䜿çšããŸããããã¯ãæ°ããã¿ã¹ã¯ãå²ãåœãŠãåã«ãã¹ã±ãžã¥ãŒã©ãŒã«äœãåŒã³åºãã¹ãããæ瀺ããæ¹æ³scheduler_free_current_task()
ã§ãã説æã«æ»ããšãscheduler_run()
ããããŸãã«ãã®æ©èœã§ããããšãããããŸãscheduler_run()
ã
ããã¯2ã€ã®ã¹ãããã§è¡ããŸããã
scheduler_exit_current_task()
ãã¿ã¹ã¯æ§é ã«å«ãŸããã¹ã¿ãã¯ãç©æ¥µçã«äœ¿çšããŸããã¹ã¿ãã¯ã解æŸããŠåŒãç¶ã䜿çšãããšã解æŸããã°ããã®ã¹ã¿ãã¯ã¡ã¢ãªã«é¢æ°ãã¢ã¯ã»ã¹ã§ããå¯èœæ§ããããŸãããããçºçããªãããã«ããã«ã¯ããã«ãlongjmp()
ã䜿çšããŠå¥ã®ã¹ã¿ãã¯ã䜿çšããŠã¹ã±ãžã¥ãŒã©ã«æ»ãå¿
èŠããããŸãããã®åŸãã¿ã¹ã¯ã«é¢é£ããããŒã¿ãå®å
šã«è§£æŸã§ããŸãã
ãã®ãããã¹ã±ãžã¥ãŒã©ã®å®è£ å šäœãå®å šã«åæããŸããããªã³ã¯ãªã¹ãã®å®è£ ãšäžèšã®ã¡ã€ã³ããã°ã©ã ãè¿œå ããŠã³ã³ãã€ã«ããããšãããšãå®å šã«æ©èœããã¹ã±ãžã¥ãŒã©ãŒãåŸãããŸããã³ããŒïŒããŒã¹ãã«ç ©ããããªãããã«ããã®èšäºã®ãã¹ãŠã®ã³ãŒããå«ãŸããŠããgithubã®ãªããžããªã«ç§»åããŸãã
説æãããŠããã¢ãããŒãã®çšéã¯äœã§ããïŒ
ãããŸã§èªãã ããšãããã°ããã®äŸãé¢çœããšçŽåŸãããå¿ èŠã¯ãªããšæããŸããããããäžèŠãããŸã圹ã«ç«ããªãããã«èŠãããããããŸãããçµå±ã®ãšãããCã§ã¯ã䞊è¡ããŠå®è¡ã§ããããããããåŒã³åºããŸã§çžäºã«åŸ æ©ããå¿ èŠããªããå®éã®ãã¹ã¬ããã䜿çšã§ããŸã
scheduler_relinquish()
ã
ãã ããããã¯ã䟿å©ãªæ©èœã®äžé£ã®ãšããµã€ãã£ã³ã°ãªå®è£ å šäœã®éå§ç¹ãšèŠãªããŠããŸããPythonã®æ°ããéåæãŠãŒãã£ãªãã£ãæ©èœããã®ãšåãããã«ãéãI / Oã¿ã¹ã¯ãã·ã³ã°ã«ã¹ã¬ããã®éåæã¢ããªã±ãŒã·ã§ã³ã®å®è£ ã«ã€ããŠè©±ãããšãã§ããŸãããã®ãããªã·ã¹ãã ã䜿çšããŠããžã§ãã¬ãŒã¿ãŒãšã³ããã³ãå®è£ ããããšãã§ããŸããæåŸã«ãããŒãã¯ãŒã¯ãããã°ããã®ã·ã¹ãã ããå®éã®ããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã¹ã¬ãããšçµã¿åãããŠãå¿ èŠã«å¿ããŠè¿œå ã®åæå®è¡æ§ãæäŸããããšãã§ããŸããèå³æ·±ããããžã§ã¯ãããããã®ã¢ã€ãã¢ã®ããããã®èåŸã«é ãããŠããŸããèªè ã®çæ§ãèªåã§ãããã®1ã€ãå®æãããããšããå§ãããŸãã
å®å šã§ãïŒ
ã¯ãããããããã®å¯èœæ§ãé«ããšæããŸãïŒã¹ã¿ãã¯ãã€ã³ã¿ã«åœ±é¿ãäžããã€ã³ã©ã€ã³ã¢ã»ã³ããªã³ãŒãã¯å®å šãšã¯èŠãªãããŸããããããã®ãã®ãæ¬çªç°å¢ã§äœ¿çšãããªã¹ã¯ãåããªãã§ãã ããããã ããããããããã£ãŠèª¿æ»ããŠãã ããã
ãã®ãããªã·ã¹ãã ã®ããå®å šãªå®è£ ã¯ããéã³ã³ããã¹ããAPIïŒman getcontextãåç §ïŒã䜿çšããŠæ§ç¯ã§ããŸããããã«ãããã¢ã»ã³ããªã³ãŒããåã蟌ãããšãªãããããã®ã¿ã€ãã®ãŠãŒã¶ãŒã¹ããŒã¹ãã¹ããªãŒã ããåãæ¿ããããšãã§ããŸããæ®å¿µãªããããã®ãããªAPIã¯æšæºã§ã«ããŒãããŠããŸããïŒPOSIXä»æ§ããåé€ãããŠããŸãïŒããã ããããã§ãglibcã®äžéšãšããŠäœ¿çšã§ããŸãã
ã©ãããã°ãã®ãããªã¡ã«ããºã ã眮ãæããããšãã§ããŸããïŒ
ããã«ç€ºãããã«ããã®ã¹ã±ãžã¥ãŒã©ãŒã¯ãã¹ã¬ãããæ瀺çã«å¶åŸ¡ãã¹ã±ãžã¥ãŒã©ãŒã«æ»ãå Žåã«ã®ã¿æ©èœããŸããããã¯ãäžè¬çãªããã°ã©ã ãããšãã°ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã«ã¯é©ããŠããŸãããã¹ã¬ããã®äœæãäžååã ãšãä»ã®ãã¹ãŠã®å®è¡ããããã¯ãããå¯èœæ§ãããããã§ãïŒãã ããMS-DOSã§ã®å調ãã«ãã¿ã¹ã¯ã®äœ¿çšã¯åŠšããããŸããã§ããïŒãããã«ãããå調ãã«ãã¿ã¹ã¯ãæããã«æªããªããšã¯æããŸãããããã¯ãã¹ãŠã¢ããªã±ãŒã·ã§ã³ã«äŸåããŸãã
éæšæºã®ãã³ã³ããã¹ãå€ãAPIã䜿çšããå ŽåãPOSIXã·ã°ãã«ã¯ã以åã«å®è¡ãããã³ãŒãã®ã³ã³ããã¹ããæ ŒçŽããŸããã¿ã€ããŒãããŒãé³ã«èšå®ããããšã«ããããŠãŒã¶ãŒã¹ããŒã¹ã¹ã±ãžã¥ãŒã©ãŒã¯å®éã«ããªãšã³ããã£ããã«ãã¿ã¹ã¯ã®åäœããŒãžã§ã³ãæäŸã§ããŸããããã¯å¥ã®èšäºã«å€ããå¥ã®ã¯ãŒã«ãªãããžã§ã¯ãã§ãã