> I'm going to try and merge the new context setup with the old jmp
> setup via ifdef's for __UCLIBC__
You should add an autoconf test that looks for setcontext or
makecontext instead. Mac OS X is in the same situation, for example.
This way, it'll switch to setjmp on any platform which doesn't have
makecontext/setcontext, hopefully making it work.
Right.
Here's a patch that doesn't do that. It simply switches back to the
old setjmp/longjmp version without using any #ifdefs at all. This
seems to still pass all the wvstreams unit tests for me.
If someone wants to change autoconf to add a
HAVE_MKCONTEXT or something, conditionally add
typedef ucontext_t WvTaskContext;
or
typedef jmpbuf WvTaskContext;
And then ifdef the rest, I think we'd have something worth committing. G.P.,
want to give it a try?
---
include/wvtask.h | 12 ++----
utils/wvtask.cc | 115 ++++++-----------------------------------------------
2 files changed, 17 insertions(+), 110 deletions(-)
diff --git a/include/wvtask.h b/include/wvtask.h
index 31c39c0..5f67844 100644
--- a/include/wvtask.h
+++ b/include/wvtask.h
@@ -24,7 +24,6 @@
#include "wvstreamsdebugger.h"
#include "wvstringlist.h"
#include "setjmp.h"
-#include <ucontext.h>
#define WVTASK_MAGIC 0x123678
@@ -50,12 +49,10 @@ class WvTask
int tid;
size_t stacksize;
- void *stack;
bool running, recycled;
WvTaskMan &man;
- ucontext_t mystate; // used for resuming the task
- ucontext_t func_call, func_return;
+ jmp_buf mystate; // used for resuming the task
TaskFunc *func;
void *userdata;
@@ -91,16 +88,15 @@ class WvTaskMan
static void stackmaster();
static void _stackmaster();
static void do_task();
- static void call_func(WvTask *task);
static char *stacktop;
- static ucontext_t stackmaster_task;
+ static jmp_buf stackmaster_task;
static WvTask *stack_target;
- static ucontext_t get_stack_return;
+ static jmp_buf get_stack_return;
static WvTask *current_task;
- static ucontext_t toplevel;
+ static jmp_buf toplevel;
WvTaskMan();
virtual ~WvTaskMan();
diff --git a/utils/wvtask.cc b/utils/wvtask.cc
index d30808b..32128a1 100644
--- a/utils/wvtask.cc
+++ b/utils/wvtask.cc
@@ -32,10 +32,6 @@ char *alloca ();
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
-#include <sys/mman.h>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/resource.h>
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
@@ -60,7 +56,7 @@ int WvTask::taskcount, WvTask::numtasks, WvTask::numrunning;
WvTaskMan *WvTaskMan::singleton;
int WvTaskMan::links, WvTaskMan::magic_number;
WvTaskList WvTaskMan::all_tasks, WvTaskMan::free_tasks;
-ucontext_t WvTaskMan::stackmaster_task, WvTaskMan::get_stack_return,
+jmp_buf WvTaskMan::stackmaster_task, WvTaskMan::get_stack_return,
WvTaskMan::toplevel;
WvTask *WvTaskMan::current_task, *WvTaskMan::stack_target;
char *WvTaskMan::stacktop;
@@ -198,9 +194,7 @@ WvTaskMan::WvTaskMan()
stacktop = (char *)alloca(0);
- context_return = 0;
- assert(getcontext(&get_stack_return) == 0);
- if (context_return == 0)
+ if (setjmp(get_stack_return) == 0)
{
// initial setup - start the stackmaster() task (never returns!)
stackmaster();
@@ -257,22 +251,18 @@ int WvTaskMan::run(WvTask &task, int val)
WvTask *old_task = current_task;
current_task = &task;
- ucontext_t *state;
+ jmp_buf *state;
if (!old_task)
state = &toplevel; // top-level call (not in an actual task yet)
else
state = &old_task->mystate;
- context_return = 0;
- assert(getcontext(state) == 0);
- int newval = context_return;
+ int newval = setjmp(*state);
if (newval == 0)
{
// saved the state, now run the task.
- context_return = val;
- setcontext(&task.mystate);
- return -1;
+ longjmp(task.mystate, val);
}
else
{
@@ -303,8 +293,6 @@ int WvTaskMan::yield(int val)
assert(*current_task->stack_magic == WVTASK_MAGIC);
#if TASK_DEBUG
- if (use_shared_stack())
- {
size_t stackleft;
char *stackbottom = (char *)(current_task->stack_magic + 1);
for (stackleft = 0; stackleft < current_task->stacksize; stackleft++)
@@ -315,18 +303,13 @@ int WvTaskMan::yield(int val)
Dprintf("WvTaskMan: remaining stack after #%d (%s): %ld/%ld\n",
current_task->tid, current_task->name.cstr(), (long)stackleft,
(long)current_task->stacksize);
- }
#endif
- context_return = 0;
- assert(getcontext(¤t_task->mystate) == 0);
- int newval = context_return;
+ int newval = setjmp(current_task->mystate);
if (newval == 0)
{
// saved the task state; now yield to the toplevel.
- context_return = val;
- setcontext(&toplevel);
- return -1;
+ longjmp(toplevel, val);
}
else
{
@@ -340,34 +323,14 @@ int WvTaskMan::yield(int val)
void WvTaskMan::get_stack(WvTask &task, size_t size)
{
- context_return = 0;
- assert(getcontext(&get_stack_return) == 0);
- if (context_return == 0)
+ if (setjmp(get_stack_return) == 0)
{
assert(magic_number == -WVTASK_MAGIC);
assert(task.magic_number == WVTASK_MAGIC);
- if (!use_shared_stack())
- {
-#if defined(__linux__) && (defined(__386__) || defined(__i386) || defined(__i386__))
- static char *next_stack_addr = (char *)0xB0000000;
- static const size_t stack_shift = 0x00100000;
-
- next_stack_addr -= stack_shift;
-#else
- static char *next_stack_addr = NULL;
-#endif
-
- task.stack = mmap(next_stack_addr, task.stacksize,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
- }
-
// initial setup
stack_target = &task;
- context_return = size/1024 + (size%1024 > 0);
- setcontext(&stackmaster_task);
+ longjmp(stackmaster_task, size/1024 + (size%1024 > 0));
}
else
{
@@ -404,9 +367,7 @@ void WvTaskMan::_stackmaster()
{
assert(magic_number == -WVTASK_MAGIC);
- context_return = 0;
- assert(getcontext(&stackmaster_task) == 0);
- val = context_return;
+ val = setjmp(stackmaster_task);
if (val == 0)
{
assert(magic_number == -WVTASK_MAGIC);
@@ -414,19 +375,13 @@ void WvTaskMan::_stackmaster()
// just did setjmp; save stackmaster's current state (with
// all current stack allocations) and go back to get_stack
// (or the constructor, if that's what called us)
- context_return = 1;
- setcontext(&get_stack_return);
+ longjmp(get_stack_return, 1);
}
else
{
valgrind_fix(stacktop);
assert(magic_number == -WVTASK_MAGIC);
- total = (val+1) * (size_t)1024;
-
- if (!use_shared_stack())
- total = 1024; // enough to save the do_task stack frame
-
// set up a stack frame for the new task. This runs once
// per get_stack.
//alloc_stack_and_switch(total);
@@ -435,6 +390,7 @@ void WvTaskMan::_stackmaster()
assert(magic_number == -WVTASK_MAGIC);
// allocate the stack area so we never use it again
+ total = (val+1) * (size_t)1024;
alloca(total);
// a little sentinel so we can detect stack overflows
@@ -451,17 +407,6 @@ void WvTaskMan::_stackmaster()
}
-void WvTaskMan::call_func(WvTask *task)
-{
- Dprintf("WvTaskMan: calling task #%d (%s)\n",
- task->tid, (const char *)task->name);
- task->func(task->userdata);
- Dprintf("WvTaskMan: returning from task #%d (%s)\n",
- task->tid, (const char *)task->name);
- context_return = 1;
-}
-
-
void WvTaskMan::do_task()
{
assert(magic_number == -WVTASK_MAGIC);
@@ -469,9 +414,7 @@ void WvTaskMan::do_task()
assert(task->magic_number == WVTASK_MAGIC);
// back here from longjmp; someone wants stack space.
- context_return = 0;
- assert(getcontext(&task->mystate) == 0);
- if (context_return == 0)
+ if (setjmp(task->mystate) == 0)
{
// done the setjmp; that means the target task now has
// a working jmp_buf all set up. Leave space on the stack
@@ -497,30 +440,10 @@ void WvTaskMan::do_task()
if (task->func && task->running)
{
- if (use_shared_stack())
- {
// this is the task's main function. It can call yield()
// to give up its timeslice if it wants. Either way, it
// only returns to *us* if the function actually finishes.
task->func(task->userdata);
- }
- else
- {
- assert(getcontext(&task->func_call) == 0);
- task->func_call.uc_stack.ss_size = task->stacksize;
- task->func_call.uc_stack.ss_sp = task->stack;
- task->func_call.uc_stack.ss_flags = 0;
- task->func_call.uc_link = &task->func_return;
- Dprintf("WvTaskMan: makecontext #%d (%s)\n",
- task->tid, (const char *)task->name);
- makecontext(&task->func_call,
- (void (*)(void))call_func, 1, task);
-
- context_return = 0;
- assert(getcontext(&task->func_return) == 0);
- if (context_return == 0)
- setcontext(&task->func_call);
- }
// the task's function terminated.
task->name = "DEAD";
@@ -536,25 +459,13 @@ void WvTaskMan::do_task()
const void *WvTaskMan::current_top_of_stack()
{
extern const void *__libc_stack_end;
- if (use_shared_stack() || current_task == NULL)
return __libc_stack_end;
- else
- return (const char *)current_task->stack + current_task->stacksize;
}
size_t WvTaskMan::current_stacksize_limit()
{
- if (use_shared_stack() || current_task == NULL)
- {
- struct rlimit rl;
- if (getrlimit(RLIMIT_STACK, &rl) == 0)
- return size_t(rl.rlim_cur);
- else
return 0;
- }
- else
- return size_t(current_task->stacksize);
}
--
1.5.4.3
That should work.
> When i try this, i got many errors! So which version did you use?
Hmm, I think it will apply to the most recent version in git.
However, you have to make sure to use a non-corrupted text version of
the message if you want it to work. Your mailer should have some kind
of "save this message as raw text" option somewhere. Don't use
cut-and-paste!
Avery
> I used copy and paste, because i watch this in the browser!
If you're using gmail (for example), you can save the original text. Click
the down arrow next to Reply, then pick Show Original. Then use File | Save
in your web browser.
> However, i change the file with an editor. But when i try to compile
> it (for Oleg-FW - Optware/NSLU Linux) i stil got some errors.
>
> Like in streams/wvistreamlist.cc:193 __assert_fail not referenced and
> __ASSERT_VOID_CAST not referenced.
>
> I figured out that this is maybe a problem when you use uClibc instead
> of glibc.
Yes, it looks like we had a #define in wvassert.h that's assuming
Linux==glibc. Try this:
commit 48c7618b0efb68c4d6dfed87f83a3263617b2937
Author: Avery Pennarun <apen...@gmail.com>
Date: Tue Sep 2 12:31:03 2008 -0400
wvassert: default to old-fashioned assert if no __GLIBC__, not just on win32.
This hopefully helps with uclibc compile problems.
diff --git a/include/wvassert.h b/include/wvassert.h
index 86d19d2..2a5eb0a 100644
--- a/include/wvassert.h
+++ b/include/wvassert.h
@@ -36,7 +36,7 @@ private:
WvString old_will;
};
-#if defined(_WIN32)
+#if !defined(__GLIBC__)
# define wvassert(expr, args...) assert(expr)
# define wvassert_perror(errnum) perror(errnum)
Googling "uclibc __assert_fail not referenced" I found this post:
http://www.uclibc.org/lists/uclibc/2002-February/002657.html
Not sure if that helps.
Joe
Did you try my patch? It's much better than removing assertions.
> (because
> the oleg firmware has not openssl 0.9.8, it has 0.9.7 and the wvstream
> needs some function from 0.9.8).
We might be able to fix that too if you post the exact errors. I'm
sure we don't use anything *important* from 0.9.7.
Have fun,
Avery
Okay. Note that I sent you two patches now, right? The second one
was to fix the assert-related problems.
> Now i try to make the program and these are the results:
> http://members.inode.at./j.taschek/errors.txt
Hmm, it's perfectly okay to post the error messages to the mailing
list rather than using a link. That way they'll be saved for
posterity in the list archives so other people can find them.
With that in mind:
> FIRST ERROR:
> streams/wvistreamlist.cc: In member function 'virtual bool
> WvIStreamList::post_select(IWvStream::SelectInfo&)':
> streams/wvistreamlist.cc:193: error: '__assert_fail' was not declared in this scope
> streams/wvistreamlist.cc:193: error: '__ASSERT_VOID_CAST' was not declared in this scope
>
> SOLUTION: i comment out the line
My assert-fixing patch should solve this more elegantly.
> SECOND ERROR:
> compiling uniconf/uniconf.o...
> ./include/uniconfkey.h: In member function 'UniConfKey UniConfKey::last(int) const':
> ./include/uniconfkey.h:330: error: 'INT_MAX' was not declared in this scope
> ./include/uniconfkey.h: In member function 'UniConfKey UniConfKey::removefirst(int) const':
> ./include/uniconfkey.h:341: error: 'INT_MAX' was not declared in this scope
>
> SOLUTION: I icnlude the limits.h in uniconfkey.h
Thanks, we should do that in the official version too.
> THIRD ERROR:
> compiling uniconf/uniconfkey.o...
> uniconf/uniconfkey.cc: In member function 'UniConfKey UniConfKey::subkey(const UniConfKey&) const':
> uniconf/uniconfkey.cc:327: error: '__assert_fail' was not declared in this scope
> uniconf/uniconfkey.cc:327: error: '__ASSERT_VOID_CAST' was not declared in this scope
> make[1]: *** [uniconf/uniconfkey.o] Error 1
>
> SOLUTION: I comment out the line
Again, the assert patch should have fixed this.
> FOURTH ERROR:
> compiling utils/wvcrashbase.o...
> utils/wvcrashbase.cc:22: error: 'program_invocation_short_name' was not declared in this scope
> make[1]: *** [utils/wvcrashbase.o] Error 1
>
> SOLUTION: I replaced the define with text "UNKOWN"
Okay for now. We probably need an autoconf test around execinfo.h.
> FITH ERROR:
> utils/wvcrash.cc:31:23: error: execinfo.h: No such file or directory
> utils/wvcrash.cc:35: error: 'program_invocation_short_name' was not declared in this scope
> utils/wvcrash.cc: In function 'void wvcrash_real(int, int, pid_t)':
> utils/wvcrash.cc:272: error: 'backtrace' was not declared in this scope
> utils/wvcrash.cc:272: error: 'backtrace_symbols_fd' was not declared in this scope
> make[1]: *** [utils/wvcrash.o] Error 1
>
> SOLUTION: i copied the execinfo.h from /usr/include to the wvstreams/include folder (oleg fw doesnt have any
> execinfo) and replaced the define with UNKNOWN (like 4)
This won't work very well when you get to linking, I imagine. Looks
like the wvcrash stuff needs to be trimmed down significantly if
execinfo.h isn't available.
> SIXTH (AND MAJOR BUG) ERROR:
> compiling crypto/wvx509.o...
> crypto/wvx509.cc: In member function 'bool WvX509::get_policy_constraints(int&, int&) const':
> crypto/wvx509.cc:816: error: 'POLICY_CONSTRAINTS' was not declared in this scope
>
> BAD SOLUTION: copy the openssl 0.9.8 h files to the include directory! But when he tries to link, the linker
> didnt find the entry points in the library (because it is 0.9.7)
Hmm, it does seem that we've accidentally acquired a dependency on
OpenSSL 0.9.8. However, it looks like this dependency is optional.
Please try completely deleting the functions that are causing the
problem in wvx509.cc; I don't think it's likely that your app calls
them anyway!
I'm going to put in a bit of work to see if I can make autoconf detect
all this stuff automatically so this problem gets solved in general.
Thanks,
Avery
Okay, if you get the latest wvstreams 'master' from git (visit
http://repo.or.cz/w/wvstreams.git and follow the links), you should
have a version that compiles with openssl 0.9.7 (although a couple of
unit tests fail strangely, see my other message). Please try it out
and let me know if it helps.
Have fun,
Avery
It's very easy to compile xplc on just about any platform, so you just
should grab that one from elsewhere. We don't rely on gnulib anymore,
because it was broken and crazy. However we do use argp, which is
included in glibc. You can also get our patched version for other
platforms by checking out the wvbuild project. Follow the link from
here:
http://repo.or.cz/w/wvstreams/wvbuild.git
xplc is in that package too, if you want it.
> Or can i just copy the .h files into the include folder?
No, then it'll compile but not link.
Good luck! I hope we're getting you there, albeit slowly. I would
really like to hear that you got it working :)
Have fun,
Avery
Right, that's normal.
> And when i tried to compile it directly on router, it reboots. I will
> give a try in the vmware/cross compile environment.
Good idea. Please also look at my previous message about checking out
the wvbuild project, which has a copy of argp that you can use.
Thanks,
Avery