From: Linas Vepstas <linasvepstas@gmail.com>
To: Neil Jerram <neil@ossau.uklinux.net>
Cc: guile-user@gnu.org, Peter Brett <peter@peter-b.co.uk>, geda-dev@seul.org
Subject: Re: Help needed debugging segfault with Guile 1.8.7
Date: Sun, 28 Nov 2010 11:21:30 -0600 [thread overview]
Message-ID: <AANLkTikAzGV1e21bZUFuqRrcQxVoi8aBDMwkZ2gpNHDZ@mail.gmail.com> (raw)
In-Reply-To: <8739ql38pe.fsf@ossau.uklinux.net>
[-- Attachment #1: Type: text/plain, Size: 2904 bytes --]
On 28 November 2010 05:38, Neil Jerram <neil@ossau.uklinux.net> wrote:
> Peter Brett <peter@peter-b.co.uk> writes:
>
>> Sure. libgeda uses direct management of memory, and the structures used
>> in its document object model need to be explicitly deleted when finished
>> with. I decided to use a Guile smob to represent these structures for
>> access from Scheme code, with the pointer to the actual structure in
>> SCM_SMOB_DATA and with the low nibble of SCM_SMOB_FLAGS indicating which
>> type of DOM structure the smob references.
>>
>> This would have been sufficient if Scheme code had only been working
>> with libgeda DOMs created and managed entirely via Scheme code. [...]
>
> I think your design is similar to what is outlined in the `Extending
> Dia' node of the Guile manual. Were you aware of that doc before
> working out your design? If not, I guess we need to make it more
> prominent. If yes, I'd appreciate any suggestions you have for how it
> may be improved.
Yes, I code almost entirely 'by example', so having a good cookbook is
critical for me. I haven't read 'Extending Dia' before, its probably more
recent than the last time I set up guile bindings, some 2-3 years ago;
I skimmed it briefly just now.
Several comments on example code:
1) its typically not possible to wrap the C main(), so having a well-defined
init() that happens some time later would be best.
2) http://www.gnu.org/software/guile/manual/html_node/Dia-Hook.html
is lame. What I have to do is this:
SCM rc = scm_c_catch (SCM_BOOL_T,
(scm_t_catch_body) scm_c_eval_string,
(void *) expr_str,
SchemeEval::catch_handler_wrapper, this,
SchemeEval::preunwind_handler_wrapper, this);
and my catch_handler and preunwind_handler are fairly involved.
Basically, if you are going to let users enter arbitrary scheme into
your app, they *will* enter malformed, broken expressions, and you
have to deal with these. Among other things, you have to give them
a clue as to what the error was -- some sort of trace, error reporting.
For me, this was implementing a REPL loop look-alike in my app.
I can't say "work-alike", I think mine *almost* works-alike, but not sure.
It took me a *long* time to figure out I needed the pre-unwind version
of things, and even then, it took me a fair amount of effort to figure
out what to put in there.
Having a section showing how to implement a repl-work-alike loop
in one's app, with reasonable debugging/stack-printing output,
would be nice to have. Figuring out how to do this one one's
own requires a lot of tenacity.
For the record, I've attched the code I wrote to do the above (and
to multi-thread, which someone later on disabled :-( Its in C++,
sorry about that, don't blame me.)
--linas
[-- Attachment #2: SchemeEval.h --]
[-- Type: text/x-chdr, Size: 3283 bytes --]
/*
* SchemeEval.h
*
* Simple scheme expression evaluator
* Copyright (c) 2008 Linas Vepstas <linas@linas.org>
*/
#ifndef OPENCOG_SCHEME_EVAL_H
#define OPENCOG_SCHEME_EVAL_H
#ifdef HAVE_GUILE
#include <string>
#include <pthread.h>
#include <libguile.h>
#include <opencog/atomspace/Handle.h>
namespace opencog {
class SchemeEval
{
private:
// Initialization stuff
void init(void);
static void * c_wrap_init(void *);
void per_thread_init(void);
void thread_lock(void);
void thread_unlock(void);
// destructor stuff
void finish(void);
static void * c_wrap_finish(void *);
// Things related to evaluation
std::string do_eval(const std::string &);
static void * c_wrap_eval(void *);
static void * c_wrap_eval_h(void *);
const std::string *pexpr;
std::string answer;
std::string input_line;
bool pending_input;
// straight-up evaluation
static SCM wrap_scm_eval(void *);
SCM do_scm_eval(SCM);
SCM do_scm_eval_str(const std::string &);
// Handle apply
Handle do_apply(const std::string& func, Handle varargs);
SCM do_apply_scm(const std::string& func, Handle varargs);
Handle hargs;
static void * c_wrap_apply(void *);
static void * c_wrap_apply_scm(void *);
// Error handling stuff
SCM error_string_port;
SCM captured_stack;
static SCM preunwind_handler_wrapper(void *, SCM, SCM);
static SCM catch_handler_wrapper(void *, SCM, SCM);
SCM preunwind_handler(SCM, SCM);
SCM catch_handler(SCM, SCM);
bool caught_error;
// printing of basic types
static std::string prt(SCM);
// output port
SCM outport;
SCM saved_outport;
// Make constructor, destructor private; force
// everyone to use the singleton instance, for now.
SchemeEval(void);
~SchemeEval();
static SchemeEval* singletonInstance;
public:
std::string eval(const std::string &);
Handle eval_h(const std::string &);
Handle apply(const std::string& func, Handle varargs);
std::string apply_generic(const std::string& func, Handle varargs);
bool input_pending(void);
void clear_pending(void);
bool eval_error(void);
// Someone thinks that there some scheme threading bug somewhere,
// and the current hack around this is to use a singleton instance.
static SchemeEval& instance(void)
{
if (!singletonInstance)
singletonInstance = new SchemeEval();
return *singletonInstance;
}
};
}
#else /* HAVE_GUILE */
#include <opencog/atomspace/Handle.h>
namespace opencog {
class SchemeEval
{
private:
static SchemeEval* singletonInstance;
public:
std::string eval(const std::string &s) { return ""; }
Handle eval_h(const std::string &s) { return Handle::UNDEFINED; }
Handle apply(const std::string &s, Handle args) {
return Handle::UNDEFINED; }
std::string apply_generic(const std::string& f, Handle args) {
return ""; }
bool input_pending(void) { return false; }
void clear_pending(void) {}
// If guile is not installed, then *every* call to eval_error()
// must report that an error occurred!
bool eval_error(void) { return true; }
static SchemeEval& instance(void)
{
if (!singletonInstance)
singletonInstance = new SchemeEval();
return *singletonInstance;
}
};
}
#endif/* HAVE_GUILE */
#endif /* OPENCOG_SCHEME_EVAL_H */
[-- Attachment #3: SchemeExec.cc --]
[-- Type: text/x-c++src, Size: 1934 bytes --]
/*
* SchemeExec.cc
*
* Execute ExecutionLink's
* Copyright (c) 2009 Linas Vepstas <linasvepstas@gmail.com>
*/
#ifdef HAVE_GUILE
#include <libguile.h>
#include <opencog/atomspace/Link.h>
#include <opencog/server/CogServer.h>
#include <boost/shared_ptr.hpp>
#include "SchemeEval.h"
#include "SchemeSmob.h"
using namespace opencog;
/**
* do_apply -- apply named function func to arguments in ListLink
* It is assumed that varargs is a ListLink, containing a list of
* atom handles. This list is unpacked, and then the fuction func
* is applied to them. If the function returns an atom handle, then
* this is returned.
*/
Handle SchemeEval::do_apply(const std::string &func, Handle varargs)
{
// Apply the function to the args
SCM sresult = do_apply_scm (func, varargs);
// If the result is a handle, return the handle.
if (!SCM_SMOB_PREDICATE(SchemeSmob::cog_handle_tag, sresult))
{
return Handle::UNDEFINED;
}
return SchemeSmob::scm_to_handle(sresult);
}
/**
* do_apply_scm -- apply named function func to arguments in ListLink
* It is assumed that varargs is a ListLink, containing a list of
* atom handles. This list is unpacked, and then the fuction func
* is applied to them. The SCM value returned by the function is returned.
*/
SCM SchemeEval::do_apply_scm( const std::string& func, Handle varargs )
{
SCM sfunc = scm_from_locale_symbol(func.c_str());
SCM expr = SCM_EOL;
// If there were args, pass the args to the function.
boost::shared_ptr<Link> largs = cogserver().getAtomSpace()->cloneLink(varargs);
if (largs)
{
const std::vector<Handle> &oset = largs->getOutgoingSet();
size_t sz = oset.size();
for (int i=sz-1; i>=0; i--)
{
Handle h = oset[i];
SCM sh = SchemeSmob::handle_to_scm(h);
expr = scm_cons(sh, expr);
}
}
expr = scm_cons(sfunc, expr);
return do_scm_eval(expr);
}
#endif
/* ===================== END OF FILE ============================ */
next prev parent reply other threads:[~2010-11-28 17:21 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-10 12:43 Help needed debugging segfault with Guile 1.8.7 Peter TB Brett
2010-11-10 21:35 ` Peter TB Brett
2010-11-11 10:52 ` Peter Brett
2010-11-11 12:37 ` Thien-Thi Nguyen
2010-11-11 14:22 ` Peter Brett
2010-11-28 11:38 ` Neil Jerram
2010-11-28 17:21 ` Linas Vepstas [this message]
2010-11-30 19:56 ` Peter TB Brett
2010-12-01 19:48 ` Andy Wingo
2010-11-30 19:43 ` Peter TB Brett
2010-12-01 13:46 ` Ludovic Courtès
2010-12-03 7:52 ` Peter TB Brett
2010-11-11 8:22 ` rixed
2010-11-11 8:33 ` Neil Jerram
2010-11-11 13:30 ` Ludovic Courtès
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=AANLkTikAzGV1e21bZUFuqRrcQxVoi8aBDMwkZ2gpNHDZ@mail.gmail.com \
--to=linasvepstas@gmail.com \
--cc=geda-dev@seul.org \
--cc=guile-user@gnu.org \
--cc=neil@ossau.uklinux.net \
--cc=peter@peter-b.co.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).