diff --git a/qse/configure b/qse/configure
index d21f2f64..705bcadf 100755
--- a/qse/configure
+++ b/qse/configure
@@ -16070,7 +16070,7 @@ fi
done
-for ac_header in time.h sys/time.h utime.h spawn.h execinfo.h
+for ac_header in time.h sys/time.h utime.h spawn.h execinfo.h ucontext.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -16260,6 +16260,18 @@ _ACEOF
fi
done
+for ac_func in makecontext swapcontext getcontext setcontext
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
for ac_func in if_nametoindex if_indextoname
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
diff --git a/qse/configure.ac b/qse/configure.ac
index 2729cb4e..6232ada7 100644
--- a/qse/configure.ac
+++ b/qse/configure.ac
@@ -83,7 +83,7 @@ AC_SUBST(LIBM, $LIBM)
dnl check header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h])
-AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h])
+AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h ucontext.h])
AC_CHECK_HEADERS([sys/resource.h sys/wait.h sys/syscall.h sys/sendfile.h sys/epoll.h])
AC_CHECK_HEADERS([sys/ioctl.h net/if.h])
@@ -107,6 +107,7 @@ AC_CHECK_FUNCS([sysconf])
AC_CHECK_FUNCS([backtrace backtrace_symbols])
AC_CHECK_FUNCS([fdopendir])
AC_CHECK_FUNCS([fork vfork posix_spawn gettid])
+AC_CHECK_FUNCS([makecontext swapcontext getcontext setcontext])
AC_CHECK_FUNCS([if_nametoindex if_indextoname])
OLDLIBS="$LIBS"
diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am
index 62a72011..fe5649ea 100644
--- a/qse/include/qse/cmn/Makefile.am
+++ b/qse/include/qse/cmn/Makefile.am
@@ -36,6 +36,7 @@ pkginclude_HEADERS = \
slmb.h \
stdio.h \
str.h \
+ task.h \
time.h \
tio.h \
tre.h \
diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in
index 62b8690a..070b1091 100644
--- a/qse/include/qse/cmn/Makefile.in
+++ b/qse/include/qse/cmn/Makefile.in
@@ -55,7 +55,7 @@ am__pkginclude_HEADERS_DIST = alg.h chr.h cp949.h cp950.h dll.h env.h \
fio.h fma.h fmt.h fs.h gdl.h glob.h htb.h hton.h ipad.h lda.h \
main.h map.h mbwc.h mem.h nwad.h nwif.h nwio.h oht.h opt.h \
path.h pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h stdio.h \
- str.h time.h tio.h tre.h uri.h utf8.h xma.h Mmgr.hpp \
+ str.h task.h time.h tio.h tre.h uri.h utf8.h xma.h Mmgr.hpp \
StdMmgr.hpp Mmged.hpp
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
@@ -247,7 +247,7 @@ pkginclude_HEADERS = alg.h chr.h cp949.h cp950.h dll.h env.h fio.h \
fma.h fmt.h fs.h gdl.h glob.h htb.h hton.h ipad.h lda.h main.h \
map.h mbwc.h mem.h nwad.h nwif.h nwio.h oht.h opt.h path.h \
pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h stdio.h str.h \
- time.h tio.h tre.h uri.h utf8.h xma.h $(am__append_1)
+ task.h time.h tio.h tre.h uri.h utf8.h xma.h $(am__append_1)
all: all-am
.SUFFIXES:
diff --git a/qse/include/qse/cmn/task.h b/qse/include/qse/cmn/task.h
new file mode 100644
index 00000000..f8bae567
--- /dev/null
+++ b/qse/include/qse/cmn/task.h
@@ -0,0 +1,54 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2012 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+#ifndef _QSE_CMN_TASK_H_
+#define _QSE_CMN_TASK_H_
+
+#include
+#include
+
+typedef void (*qse_task_fnc_t) (void* ctx);
+
+typedef struct qse_task_t qse_task_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int qse_gettaskid (
+ qse_task_t* task
+);
+
+qse_task_t* qse_maketask (
+ qse_task_fnc_t fnc,
+ void* ctx,
+ qse_size_t stsize
+);
+
+int qse_task_boot (
+ void
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in
index 3e384ae2..f20ba3fd 100644
--- a/qse/include/qse/config.h.in
+++ b/qse/include/qse/config.h.in
@@ -112,6 +112,9 @@
/* Define to 1 if you have the `ftruncate64' function. */
#undef HAVE_FTRUNCATE64
+/* Define to 1 if you have the `getcontext' function. */
+#undef HAVE_GETCONTEXT
+
/* Define to 1 if you have the `gethostbyname' function. */
#undef HAVE_GETHOSTBYNAME
@@ -160,6 +163,9 @@
/* Define to 1 if you have the `lstat64' function. */
#undef HAVE_LSTAT64
+/* Define to 1 if you have the `makecontext' function. */
+#undef HAVE_MAKECONTEXT
+
/* Define to 1 if you have the `mbrlen' function. */
#undef HAVE_MBRLEN
@@ -226,6 +232,9 @@
/* Define to 1 if you have the `sendfilev64' function. */
#undef HAVE_SENDFILEV64
+/* Define to 1 if you have the `setcontext' function. */
+#undef HAVE_SETCONTEXT
+
/* Define to 1 if you have the header file. */
#undef HAVE_SIGNAL_H
@@ -289,6 +298,9 @@
/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+/* Define to 1 if you have the `swapcontext' function. */
+#undef HAVE_SWAPCONTEXT
+
/* Define to 1 if you have the `sysconf' function. */
#undef HAVE_SYSCONF
@@ -348,6 +360,9 @@
/* Define to 1 if you have the `towctrans' function. */
#undef HAVE_TOWCTRANS
+/* Define to 1 if you have the header file. */
+#undef HAVE_UCONTEXT_H
+
/* Define to 1 if you have the header file. */
#undef HAVE_UNISTD_H
diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am
index f9863ff1..3d0dda25 100644
--- a/qse/lib/cmn/Makefile.am
+++ b/qse/lib/cmn/Makefile.am
@@ -92,6 +92,7 @@ libqsecmn_la_SOURCES = \
str-tok.c \
str-trm.c \
str-word.c \
+ task.c \
time.c \
tio.c \
tre.c \
diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in
index 888cfda8..10f3013d 100644
--- a/qse/lib/cmn/Makefile.in
+++ b/qse/lib/cmn/Makefile.in
@@ -94,7 +94,7 @@ am_libqsecmn_la_OBJECTS = alg-base64.lo alg-rand.lo alg-search.lo \
str-incl.lo str-len.lo str-pac.lo str-pbrk.lo str-put.lo \
str-rev.lo str-rot.lo str-set.lo str-spl.lo str-spn.lo \
str-str.lo str-subst.lo str-tok.lo str-trm.lo str-word.lo \
- time.lo tio.lo tre.lo tre-ast.lo tre-compile.lo \
+ task.lo time.lo tio.lo tre.lo tre-ast.lo tre-compile.lo \
tre-match-backtrack.lo tre-match-parallel.lo tre-parse.lo \
tre-stack.lo uri.lo utf8.lo xma.lo
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
@@ -382,6 +382,7 @@ libqsecmn_la_SOURCES = \
str-tok.c \
str-trm.c \
str-word.c \
+ task.c \
time.c \
tio.c \
tre.c \
@@ -550,6 +551,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-tok.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-trm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-word.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tre-ast.Plo@am__quote@
diff --git a/qse/lib/cmn/syscall.h b/qse/lib/cmn/syscall.h
index a1382eec..ed893e0f 100644
--- a/qse/lib/cmn/syscall.h
+++ b/qse/lib/cmn/syscall.h
@@ -518,9 +518,9 @@ and restores it after interrupt.
*/
#define QSE_SYSCALL1(ret,num,arg1) \
__asm__ volatile ( \
- "push %%ebx\n" \
- "movl %2, %%ebx\n" \
- "int $0x80\n" \
+ "push %%ebx\n\t" \
+ "movl %2, %%ebx\n\t" \
+ "int $0x80\n\t" \
"pop %%ebx\n" \
: "=a"(ret) \
: "a"((qse_uint32_t)num), "r"((qse_uint32_t)arg1) \
@@ -538,9 +538,9 @@ and restores it after interrupt.
*/
#define QSE_SYSCALL2(ret,num,arg1,arg2) \
__asm__ volatile ( \
- "push %%ebx\n" \
- "movl %2, %%ebx\n" \
- "int $0x80\n" \
+ "push %%ebx\n\t" \
+ "movl %2, %%ebx\n\t" \
+ "int $0x80\n\t" \
"pop %%ebx\n" \
: "=a"(ret) \
: "a"((qse_uint32_t)num), "r"((qse_uint32_t)arg1), "c"((qse_uint32_t)arg2) \
@@ -558,9 +558,9 @@ and restores it after interrupt.
*/
#define QSE_SYSCALL3(ret,num,arg1,arg2,arg3) \
__asm__ volatile ( \
- "push %%ebx\n" \
- "movl %2, %%ebx\n" \
- "int $0x80\n" \
+ "push %%ebx\n\t" \
+ "movl %2, %%ebx\n\t" \
+ "int $0x80\n\t" \
"pop %%ebx\n" \
: "=a"(ret) \
: "a"((qse_uint32_t)num), "r"((qse_uint32_t)arg1), "c"((qse_uint32_t)arg2), "d"((qse_uint32_t)arg3) \
@@ -569,9 +569,9 @@ and restores it after interrupt.
#define QSE_SYSCALL4(ret,num,arg1,arg2,arg3,arg4) \
__asm__ volatile ( \
- "push %%ebx\n" \
- "movl %2, %%ebx\n" \
- "int $0x80\n" \
+ "push %%ebx\n\t" \
+ "movl %2, %%ebx\n\t" \
+ "int $0x80\n\t" \
"pop %%ebx\n" \
: "=a"(ret) \
: "a"((qse_uint32_t)num), "r"((qse_uint32_t)arg1), "c"((qse_uint32_t)arg2), "d"((qse_uint32_t)arg3), "S"((qse_uint32_t)arg4) \
diff --git a/qse/lib/cmn/task.c b/qse/lib/cmn/task.c
new file mode 100644
index 00000000..a676083d
--- /dev/null
+++ b/qse/lib/cmn/task.c
@@ -0,0 +1,460 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2012 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+#include
+
+#if defined(_WIN64)
+# include
+#else
+# if defined(HAVE_UCONTEXT_H)
+# include
+# endif
+# include
+#endif
+
+typedef struct tmgr_t tmgr_t;
+struct tmgr_t
+{
+ int count;
+ int idinc;
+
+ qse_task_t* dead;
+ qse_task_t* current;
+ qse_task_t* head;
+ qse_task_t* tail;
+
+#if defined(_WIN64)
+ void* fiber;
+#elif defined(HAVE_SWAPCONTEXT)
+ ucontext_t uctx;
+#else
+ jmp_buf backjmp;
+#endif
+};
+
+struct qse_task_t
+{
+ /* queue */
+ tmgr_t* tmgr;
+
+ int id;
+
+ qse_task_fnc_t fnc;
+ void* ctx;
+ qse_size_t stsize;
+
+#if defined(_WIN64)
+ void* fiber;
+#elif defined(HAVE_SWAPCONTEXT)
+ ucontext_t uctx;
+#else
+ jmp_buf jmpbuf;
+#endif
+
+ qse_task_t* prev;
+ qse_task_t* next;
+};
+
+static tmgr_t* tmgr;
+
+qse_task_t* qse_task_alloc (qse_task_fnc_t fnc, void* ctx, qse_size_t stsize)
+{
+ qse_task_t* task;
+
+ task = malloc (QSE_SIZEOF(*task) + stsize);
+ if (task == QSE_NULL) return QSE_NULL;
+
+ //QSE_MEMSET (task, 0, QSE_SIZEOF(*task));
+ QSE_MEMSET (task, 0, QSE_SIZEOF(*task) + stsize);
+ task->tmgr = tmgr;
+ task->fnc = fnc;
+ task->ctx = ctx;
+ task->stsize = stsize;
+
+ if (tmgr->head)
+ {
+ task->next= tmgr->head;
+ tmgr->head->prev = task;
+ tmgr->head = task;
+ }
+ else
+ {
+ tmgr->head = task;
+ tmgr->tail = task;
+ }
+
+ task->id = tmgr->idinc;
+ tmgr->count++;
+ tmgr->idinc++;
+
+ return task;
+}
+
+static void purge_dead_tasks (void)
+{
+ qse_task_t* x;
+
+ while (tmgr->dead)
+ {
+ x = tmgr->dead;
+ tmgr->dead = x->next;
+#if defined(_WIN64)
+ DeleteFiber (x->fiber);
+#endif
+ free (x);
+ }
+}
+
+void qse_task_schedule (void)
+{
+ qse_task_t* current;
+
+ current = tmgr->current; /* old current */
+ tmgr->current = current->next? current->next: tmgr->head;
+
+#if defined(_WIN64)
+ /* current->fiber is handled by SwitchToFiber() implicitly */
+ SwitchToFiber (tmgr->current->fiber);
+ purge_dead_tasks ();
+#elif defined(HAVE_SWAPCONTEXT)
+ swapcontext (¤t->uctx, &tmgr->current->uctx);
+ purge_dead_tasks ();
+#else
+//printf ("switch from %d to %d\n", current->id, tmgr->current->id);
+ if (setjmp (current->jmpbuf) != 0)
+ {
+ purge_dead_tasks ();
+ return;
+ }
+ longjmp (tmgr->current->jmpbuf, 1);
+#endif
+}
+
+static void purge_current_task (void)
+{
+ qse_task_t* current;
+
+ if (tmgr->count == 1)
+ {
+ /* to purge later */
+ tmgr->current->next = tmgr->dead;
+ tmgr->dead = tmgr->current;
+
+ tmgr->current = QSE_NULL;
+ tmgr->head = QSE_NULL;
+ tmgr->tail = QSE_NULL;
+ tmgr->count = 0;
+ tmgr->idinc = 0;
+
+#if defined(_WIN64)
+ SwitchToFiber (tmgr->fiber);
+#elif defined(HAVE_SWAPCONTEXT)
+ setcontext (&tmgr->uctx);
+#else
+ longjmp (tmgr->backjmp, 1);
+#endif
+ assert (!"must not reach here....");
+ }
+
+ current = tmgr->current;
+ tmgr->current = current->next? current->next: tmgr->head;
+
+ if (current->prev) current->prev->next = current->next;
+ if (current->next) current->next->prev = current->prev;
+ if (current == tmgr->head) tmgr->head = current->next;
+ if (current == tmgr->tail) tmgr->tail = current->prev;
+ tmgr->count--;
+
+ /* to purge later */
+ current->next = tmgr->dead;
+ tmgr->dead = current;
+
+#if defined(_WIN64)
+ SwitchToFiber (tmgr->current->fiber);
+#elif defined(HAVE_SWAPCONTEXT)
+ setcontext (&tmgr->current->uctx);
+#else
+ longjmp (tmgr->current->jmpbuf, 1);
+#endif
+}
+
+#if defined(_WIN64)
+static void __stdcall execute_current_task (void* task)
+{
+ assert (tmgr->current != QSE_NULL);
+ tmgr->current->fnc (tmgr->current->ctx);
+ purge_current_task ();
+}
+#else
+
+static void execute_current_task (void)
+{
+ assert (tmgr->current != QSE_NULL);
+
+ tmgr->current->fnc (tmgr->current->ctx);
+
+ /* the task function is now terminated. we need to
+ * purge it from the task list */
+ purge_current_task ();
+}
+#endif
+
+static qse_task_t* xxtask;
+static void* xxoldsp;
+
+#if defined(__WATCOMC__)
+/* for watcom, i support i386/32bit only */
+extern void* set_sp (void*);
+#pragma aux set_sp = \
+ "xchg eax, esp" \
+ parm [eax] value [eax] modify [esp]
+#endif
+
+qse_task_t* qse_maketask (qse_task_fnc_t fnc, void* ctx, qse_size_t stsize)
+{
+ qse_task_t* task;
+ void* newsp;
+
+
+#if defined(_WIN64)
+ task = qse_task_alloc (fnc, ctx, 0);
+ if (task == QSE_NULL) return QSE_NULL;
+
+ task->fiber = CreateFiberEx (stsize, stsize, FIBER_FLAG_FLOAT_SWITCH, execute_current_task, QSE_NULL);
+ if (task->fiber == QSE_NULL)
+ {
+/* TODO: delete task */
+ return QSE_NULL;
+ }
+
+#elif defined(HAVE_SWAPCONTEXT)
+
+ task = qse_task_alloc (fnc, ctx, stsize);
+ if (task == QSE_NULL) return QSE_NULL;
+
+ if (getcontext (&task->uctx) <= -1)
+ {
+/* TODO: delete task */
+ return QSE_NULL;
+ }
+ task->uctx.uc_stack.ss_sp = task + 1;
+ task->uctx.uc_stack.ss_size = stsize;
+ task->uctx.uc_link = QSE_NULL;
+ makecontext (&task->uctx, execute_current_task, 0);
+
+#else
+
+ task = qse_task_alloc (fnc, ctx, stsize);
+ if (task == QSE_NULL) return QSE_NULL;
+
+ /* setjmp() doesn't allow different stacks for
+ * each execution content. let me use some assembly
+ * to change the stack pointer so that setjmp() remembers
+ * the new stack pointer for longjmp() later.
+ *
+ * this stack is used for the task function when
+ * longjmp() is made. */
+ xxtask = task;
+ newsp = ((qse_uint8_t*)(task + 1)) + stsize - QSE_SIZEOF(void*);
+
+#if defined(__WATCOMC__)
+
+ xxoldsp = set_sp (newsp);
+
+#elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64))
+
+ /*
+ __asm__ volatile (
+ "xchgq %0, %%rsp\n"
+ : "=r"(xxoldsp)
+ : "0"(newsp)
+ : "%rsp"
+ );
+ */
+
+ __asm__ volatile (
+ "movq %%rsp, %0\n\t"
+ "movq %1, %%rsp\n"
+ : "=m"(xxoldsp)
+ : "r"(newsp)
+ : "%rsp", "memory"
+ );
+
+#elif defined(__GNUC__) && (defined(__i386) || defined(i386))
+ __asm__ volatile (
+ "xchgl %0, %%esp\n"
+ : "=r"(xxoldsp)
+ : "0"(newsp)
+ : "%esp"
+ );
+#elif defined(__GNUC__) && (defined(__mips) || defined(mips))
+ __asm__ volatile (
+ "sw $sp, %0\n\t" /* store $sp to xxoldsp */
+ "move $sp, %1\n" /* move the register content for newsp to $sp */
+ : "=m"(xxoldsp)
+ : "r"(newsp)
+ : "$sp", "memory"
+ );
+ /*
+ __asm__ volatile (
+ "move %0, $sp\n\t"
+ "move $sp, %1\n"
+ : "=&r"(xxoldsp)
+ : "r"(newsp)
+ : "$sp", "memory"
+ );
+ */
+
+#elif defined(__GNUC__) && defined(__arm__)
+ __asm__ volatile (
+ "str sp, %0\n\t"
+ "mov sp, %1\n"
+ : "=m"(xxoldsp)
+ : "r"(newsp)
+ : "sp", "memory"
+ );
+
+/* TODO: support more architecture */
+#else
+
+ /* TODO: destroy task */
+ //tmgr->errnum = QSE_TMGR_ENOIMPL;
+ return QSE_NULL;
+
+#endif /* __WATCOMC__ */
+
+ /*
+ * automatic variables like 'task' and 'newsp' exist
+ * in the old stack. i can't access them.
+ * i access some key informaton via the global
+ * variables stored before stack pointer switching.
+ *
+ * this approach makes this function thread-unsafe.
+ */
+
+ /* when qse_maketask() is called,
+ * setjmp() saves the context and return 0.
+ *
+ * subsequently, when longjmp() is made
+ * for this saved context, setjmp() returns
+ * a non-zero value.
+ */
+ if (setjmp (xxtask->jmpbuf) != 0)
+ {
+ /* longjmp() is made to here. */
+ execute_current_task ();
+ assert (!"must never reach here....\n");
+ }
+
+ /* restore the stack pointer once i finish saving the longjmp() context.
+ * this part is reached only when qse_maketask() is invoked. */
+#if defined(__WATCOMC__)
+
+ set_sp (xxoldsp);
+
+#elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64))
+ __asm__ volatile (
+ "movq %0, %%rsp\n"
+ :
+ : "m"(xxoldsp) /*"r"(xxoldsp)*/
+ : "%rsp"
+ );
+
+#elif defined(__GNUC__) && (defined(__i386) || defined(i386))
+ __asm__ volatile (
+ "movl %0, %%esp\n"
+ :
+ : "r"(xxoldsp)
+ : "%esp"
+ );
+
+#elif defined(__GNUC__) && (defined(__mips) || defined(mips))
+ __asm__ volatile (
+ "lw $sp, %0\n" /*"move $sp, %0\n" */
+ :
+ : "m"(xxoldsp) /* "r"(xxoldsp) */
+ : "$sp"
+ );
+#elif defined(__GNUC__) && defined(__arm__)
+ __asm__ volatile (
+ "ldr sp, %0\n"
+ :
+ : "m"(xxoldsp)
+ : "sp"
+ );
+#endif /* __WATCOMC__ */
+
+#endif
+
+ return task;
+}
+
+int qse_gettaskid (qse_task_t* task)
+{
+ return task->id;
+}
+
+int qse_task_boot (void)
+{
+ if (tmgr->count <= 0) return -1;
+
+#if defined(_WIN64)
+ tmgr->fiber = ConvertThreadToFiberEx (QSE_NULL, FIBER_FLAG_FLOAT_SWITCH);
+ if (tmgr->fiber == QSE_NULL)
+ {
+/*TODO: destroy all the tasks created */
+ return -1;
+ }
+
+ tmgr->current = tmgr->tail;
+ SwitchToFiber (tmgr->current->fiber);
+ ConvertFiberToThread ();
+
+#elif defined(HAVE_SWAPCONTEXT)
+
+ tmgr->current = tmgr->tail;
+ if (swapcontext (&tmgr->uctx, &tmgr->current->uctx) <= -1)
+ {
+/*TODO: destroy all the tasks created */
+ return -1;
+ }
+
+#else
+ if (setjmp (tmgr->backjmp) != 0)
+ {
+ /* longjmp() back */
+ goto done;
+ }
+
+ tmgr->current = tmgr->tail;
+ longjmp (tmgr->current->jmpbuf, 1);
+ assert (!"must never reach here");
+
+done:
+#endif
+
+ assert (tmgr->current == QSE_NULL);
+ assert (tmgr->count == 0);
+
+ purge_dead_tasks ();
+ printf ("END OF TASK_BOOT...\n");
+ return 0;
+}
+
diff --git a/qse/lib/net/httpd-cgi.c b/qse/lib/net/httpd-cgi.c
index 705ac4e4..73c8c506 100644
--- a/qse/lib/net/httpd-cgi.c
+++ b/qse/lib/net/httpd-cgi.c
@@ -470,10 +470,6 @@ static int cgi_add_env (
qse_nwadtombs (&client->remote_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_ADDR);
qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), buf);
-#if 0
- qse_env_insertmbs (env, "REMOTE_USER",
-#endif
-
ctx.httpd = httpd;
ctx.env = env;
if (qse_htre_walkheaders (req, cgi_capture_client_header, &ctx) <= -1) return -1;