RPM Package Manager, CVS Repository http://rpm5.org/cvs/ ____________________________________________________________________________
Server: rpm5.org Name: Eric Veith Root: /v/rpm/cvs Email: eve...@rpm5.org Module: rpm Date: 18-Sep-2010 18:37:06 Branch: HEAD Handle: 2010091816370600 Modified files: rpm/rpmio rpmruby.c rpmruby.h Log: Prevented embedded Ruby interpreter from being initialized twice Summary: Revision Changes Path 2.16 +101 -71 rpm/rpmio/rpmruby.c 2.9 +110 -53 rpm/rpmio/rpmruby.h ____________________________________________________________________________ patch -p0 <<'@@ .' Index: rpm/rpmio/rpmruby.c ============================================================================ $ cvs diff -u -r2.15 -r2.16 rpmruby.c --- rpm/rpmio/rpmruby.c 16 Aug 2010 13:17:41 -0000 2.15 +++ rpm/rpmio/rpmruby.c 18 Sep 2010 16:37:06 -0000 2.16 @@ -1,28 +1,28 @@ #include "system.h" #include <argv.h> -/* XXX grrr, ruby.h includes its own config.h too. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#undef PACKAGE_NAME -#undef PACKAGE_TARNAME -#undef PACKAGE_VERSION -#undef PACKAGE_STRING -#undef PACKAGE_BUGREPORT + #if defined(WITH_RUBYEMBED) + +/* Make sure Ruby's fun stuff has its own xmalloc & Co functions available */ + +#undef xmalloc +#undef xcalloc +#undef xrealloc + #include <ruby.h> -#if !defined(RSTRING_PTR) -/* XXX retrofit for ruby-1.8.5 in CentOS5 */ -#define RSTRING_PTR(s) (RSTRING(s)->ptr) -#define RSTRING_LEN(s) (RSTRING(s)->len) #endif -#endif -#define _RPMRUBY_INTERNAL +/** + * Allows access to the gory details of rpmruby pool items. + */ +#define _RPMRUBY_INTERNAL 1 #include "rpmruby.h" #include "debug.h" @@ -33,22 +33,42 @@ /*...@unchecked@*/ /*...@relnull@*/ rpmruby _rpmrubyI = NULL; -static void rpmrubyFini(void * _ruby) + + +/** + * Finalizes a Ruby interpreter instance/pool item + */ +static void rpmrubyFini(void *_ruby) /*...@globals fileSystem @*/ /*...@modifies *_ruby, fileSystem @*/ { rpmruby ruby = _ruby; -#if defined(WITH_RUBYEMBED) - ruby_finalize(); - ruby_cleanup(0); -#endif +# if defined(WITH_RUBYEMBED) + ruby_cleanup(0); +# endif ruby->I = NULL; } + +/** +* The pool of Ruby interpreter instances +* @see rpmioPool +*/ /*...@unchecked@*/ /*...@only@*/ /*...@null@*/ rpmioPool _rpmrubyPool; + +/** + * Returns the current rpmio pool responsible for Ruby interpreter instances + * + * This is a wrapper function that returns the current rpmio pool responsible + * for embedded Ruby interpreters. It creates and initializes a new pool when + * there is no current pool. + * + * @return The current pool + * @see rpmioNewPool + */ static rpmruby rpmrubyGetPool(/*...@null@*/ rpmioPool pool) /*...@globals _rpmrubyPool, fileSystem @*/ /*...@modifies pool, _rpmrubyPool, fileSystem @*/ @@ -57,90 +77,100 @@ if (_rpmrubyPool == NULL) { _rpmrubyPool = rpmioNewPool("ruby", sizeof(*ruby), -1, _rpmruby_debug, - NULL, NULL, rpmrubyFini); + NULL, NULL, rpmrubyFini); pool = _rpmrubyPool; - } + } + return (rpmruby) rpmioGetPool(pool, sizeof(*ruby)); } + /*...@unchecked@*/ #if defined(WITH_RUBYEMBED) + +/** Initializes Ruby's StringIO for storing output in a string. */ static const char * rpmrubyInitStringIO = "\ require 'stringio'\n\ $stdout = StringIO.new($result, \"w+\")\n\ "; + #endif -static rpmruby rpmrubyI(void) - /*...@globals _rpmrubyI @*/ - /*...@modifies _rpmrubyI @*/ + +static rpmruby rpmrubyI() + /*...@globals _rpmrubyI @*/ + /*...@modifies _rpmrubyI @*/ { - if (_rpmrubyI == NULL) - _rpmrubyI = rpmrubyNew(NULL, 0); + if (NULL == _rpmrubyI) { + _rpmrubyI = rpmrubyNew(NULL, 0); + } return _rpmrubyI; } -rpmruby rpmrubyNew(char ** av, uint32_t flags) -{ - rpmruby ruby = -#ifdef NOTYET - (flags & 0x80000000) ? rpmrubyI() : -#endif - rpmrubyGetPool(_rpmrubyPool); - - static char * _av[] = { "rpmruby", NULL }; - if (av == NULL) av = _av; +rpmruby rpmrubyNew(char **av, uint32_t flags) +{ + /* TODO: Once Ruby allows several interpreter instances, distinguish + * between the global interpreter (1<<31 flag) and a new one. + */ + + if (NULL != _rpmrubyI) { + return _rpmrubyI; + } -#if defined(WITH_RUBYEMBED) - ruby_init(); - ruby_init_loadpath(); - ruby_script((char *)av[0]); - ruby_set_argv(argvCount((ARGV_t)av)-1, av+1); - rb_gv_set("$result", rb_str_new2("")); - (void) rpmrubyRun(ruby, rpmrubyInitStringIO, NULL); -#endif + rpmruby ruby = rpmrubyGetPool(_rpmrubyPool); - return rpmrubyLink(ruby); -} + static char *_av[] = { "rpmruby", NULL }; + if (NULL == av) { + av = _av; + } -rpmRC rpmrubyRunFile(rpmruby ruby, const char * fn, const char ** resultp) -{ - rpmRC rc = RPMRC_FAIL; -if (_rpmruby_debug) -fprintf(stderr, "==> %s(%p,%s)\n", __FUNCTION__, ruby, fn); + /* Set up embedded Ruby interpreter if embedded Ruby is enabled. */ - if (ruby == NULL) ruby = rpmrubyI(); +# if defined(WITH_RUBYEMBED) + RUBY_INIT_STACK; + ruby_init(); + ruby_init_loadpath(); + + ruby_script((char *)av[0]); + rb_gv_set("$result", rb_str_new2("")); + (void) rpmrubyRun(ruby, rpmrubyInitStringIO, NULL); +# endif - if (fn != NULL) { -#if defined(WITH_RUBYEMBED) - rb_load_file(fn); - ruby->state = ruby_exec(); - if (resultp != NULL) - *resultp = RSTRING_PTR(rb_gv_get("$result")); - rc = RPMRC_OK; -#endif - } - return rc; + return rpmrubyLink(ruby); } -rpmRC rpmrubyRun(rpmruby ruby, const char * str, const char ** resultp) + +rpmRC rpmrubyRun(rpmruby ruby, const char *str, const char **resultp) { rpmRC rc = RPMRC_FAIL; -if (_rpmruby_debug) -fprintf(stderr, "==> %s(%p,%s,%p)\n", __FUNCTION__, ruby, str, resultp); + if (_rpmruby_debug) { + fprintf(stderr, "==> %s(%p,%s,%p)\n", + __FUNCTION__, ruby, str, resultp); + } - if (ruby == NULL) ruby = rpmrubyI(); + if (NULL == ruby) { + ruby = rpmrubyI(); + } - if (str != NULL) { -#if defined(WITH_RUBYEMBED) - ruby->state = rb_eval_string(str); - if (resultp != NULL) - *resultp = RSTRING_PTR(rb_gv_get("$result")); - rc = RPMRC_OK; -#endif + if (NULL != str) { +# if defined(WITH_RUBYEMBED) + int state = -1; + ruby->state = rb_eval_string_protect(str, &state); + + /* Check whether the evaluation was successful or not */ + + if(0 == state) { + rc = RPMRC_OK; + if (resultp != NULL) { + *resultp = RSTRING_PTR(rb_gv_get("$result")); + } + } +# endif } + return rc; } + @@ . patch -p0 <<'@@ .' Index: rpm/rpmio/rpmruby.h ============================================================================ $ cvs diff -u -r2.8 -r2.9 rpmruby.h --- rpm/rpmio/rpmruby.h 7 Apr 2010 03:20:06 -0000 2.8 +++ rpm/rpmio/rpmruby.h 18 Sep 2010 16:37:06 -0000 2.9 @@ -1,108 +1,165 @@ #ifndef RPMRUBY_H #define RPMRUBY_H -/** \ingroup rpmio + +/** * \file rpmio/rpmruby.h + * \ingroup rpmio + * + * Embedded Ruby interpreter + * + * This allows the embedding of the Ruby interpreter into RPM5. It can be + * used, for example, for expanding in the fashion of + * <tt>%%expand{ruby ...}</tt>. + * + * Currently (as of ruby-1.9.2), the Ruby interpreter allows only one instance + * of itself per process. As such, rpmio's pooling mechanism will also always + * contain only one ::rpmruby instance. Calling rpmrubyNew() will initialize + * a new interpreter, while rpmrubyFree() beds this instance. Make sure you + * keep things in order, that is, call rpmrubyNew() exactly once, and don't + * forget to call rpmrubyFree() when you're done. Repeatedly calling + * rpmrubyNew will have no effect while an interpreter is allocated. + * + * You can use rpmrubyRun() to evaluate Ruby code and get the result back. */ + #include <rpmiotypes.h> #include <rpmio.h> -typedef /*...@abstract@*/ /*...@refcounted@*/ struct rpmruby_s * rpmruby; +/** Triggers printing of debugging information */ /*...@unchecked@*/ extern int _rpmruby_debug; +typedef /*...@abstract@*/ /*...@refcounted@*/ struct rpmruby_s* rpmruby; + +/** + * Current (global) interpreter instance + * + * At the moment, this variable is merely a safeguard against initializing the + * Ruby interpreter over and over again. In the future, when there is Ruby + * support for multiple interpreter instances, a flag given to rpmrubyNew() + * will use this variable and return the global interpreter instance. + */ /*...@unchecked@*/ /*...@relnull@*/ extern rpmruby _rpmrubyI; + #if defined(_RPMRUBY_INTERNAL) + +/** + * Instances of this struct carry an embedded Ruby interpreter and the state + * associated with it. + */ struct rpmruby_s { - struct rpmioItem_s _item; /*!< usage mutex and pool identifier. */ - void * I; + + /** + * Pool identifier, including usage mutex, etc. + * \see rpmioItem_s + */ + struct rpmioItem_s _item; + + /** The actual interpreter instance */ + void *I; + + /** + * Carries the interpreter's current state, e.g. the latest return code. + * */ unsigned long state; + #if defined(__LCLINT__) -/*...@refs@*/ - int nrefs; /*!< (unused) keep splint happy */ + /** Reference count: Currently unused, only to keep splint happy. */ + /*...@refs@*/ + int nrefs; #endif }; + #endif /* _RPMRUBY_INTERNAL */ + #ifdef __cplusplus extern "C" { #endif + /** - * Unreference a ruby interpreter instance. - * @param ruby ruby interpreter - * @return NULL on last dereference + * Dereferences a Ruby interpreter instance in the rpmio pool + * + * @param ruby Ruby interpreter pool item + * @return NULL on last dereference + * @see rpmUnlinkPoolItem */ /*...@unused@*/ /*...@null@*/ rpmruby rpmrubyUnlink (/*...@killref@*/ /*...@only@*/ /*...@null@*/ rpmruby ruby) - /*...@modifies ruby @*/; -#define rpmrubyUnlink(_ruby) \ - ((rpmruby)rpmioUnlinkPoolItem((rpmioItem)(_ruby), __FUNCTION__, __FILE__, __LINE__)) + /*...@modifies ruby @*/; +#define rpmrubyUnlink(_ruby) \ + ((rpmruby)rpmioUnlinkPoolItem((rpmioItem)(_ruby), __FUNCTION__, \ + __FILE__, __LINE__)) + /** - * Reference a ruby interpreter instance. - * @param ruby ruby interpreter - * @return new ruby interpreter reference + * References a Ruby interpreter instance in the rpmio pool + * + * @param ruby Ruby interpreter + * @return A new ruby interpreter reference + * @see rpmioLinkPoolItem */ /*...@unused@*/ /*...@newref@*/ /*...@null@*/ rpmruby rpmrubyLink (/*...@null@*/ rpmruby ruby) /*...@modifies ruby @*/; -#define rpmrubyLink(_ruby) \ - ((rpmruby)rpmioLinkPoolItem((rpmioItem)(_ruby), __FUNCTION__, __FILE__, __LINE__)) +#define rpmrubyLink(_ruby) \ + ((rpmruby)rpmioLinkPoolItem((rpmioItem)(_ruby), __FUNCTION__, \ + __FILE__, __LINE__)) + /** - * Destroy a ruby interpreter. - * @param ruby ruby interpreter - * @return NULL on last dereference + * Destroys a Ruby interpreter instance in the rpmio pool + * + * @param ruby The Ruby interpreter to be destroyed + * @return NULL on last dereference + * @see rpmioFreePoolItem */ /*...@null@*/ -rpmruby rpmrubyFree(/*...@killref@*/ /*...@null@*/rpmruby ruby) +rpmruby rpmrubyFree(/*...@killref@*/ /*...@null@*/ rpmruby ruby) /*...@globals fileSystem @*/ /*...@modifies ruby, fileSystem @*/; #define rpmrubyFree(_ruby) \ - ((rpmruby)rpmioFreePoolItem((rpmioItem)(_ruby), __FUNCTION__, __FILE__, __LINE__)) + ((rpmruby)rpmioFreePoolItem((rpmioItem)(_ruby), __FUNCTION__, \ + __FILE__, __LINE__)) + /** - * Create and load a ruby interpreter. - * @param av ruby interpreter args (or NULL) - * @param flags ruby interpreter flags ((1<<31): use global interpreter) - * @return new ruby interpreter + * Creates and initializes a Ruby interpreter + * + * @param av Arguments to the Ruby interpreter (may be NULL) + * @param flags Ruby interpreter flags; ((1<<31): use global interpreter) + * @return A new Ruby interpreter */ /*...@newref@*/ /*...@null@*/ -rpmruby rpmrubyNew(/*...@null@*/ char ** av, uint32_t flags) - /*...@globals fileSystem, internalState @*/ - /*...@modifies fileSystem, internalState @*/; - -/** - * Execute ruby from a file. - * @param ruby ruby interpreter (NULL uses global interpreter) - * @param fn ruby file to run (NULL returns RPMRC_FAIL) - * @param *resultp ruby exec result - * @return RPMRC_OK on success - */ -rpmRC rpmrubyRunFile(rpmruby ruby, /*...@null@*/ const char * fn, - /*...@null@*/ const char ** resultp) - /*...@globals fileSystem, internalState @*/ - /*...@modifies ruby, fileSystem, internalState @*/; - -/** - * Execute ruby string. - * @param ruby ruby interpreter (NULL uses global interpreter) - * @param str ruby string to execute (NULL returns RPMRC_FAIL) - * @param *resultp ruby exec result - * @return RPMRC_OK on success - */ -rpmRC rpmrubyRun(rpmruby ruby, /*...@null@*/ const char * str, - /*...@null@*/ const char ** resultp) - /*...@globals fileSystem, internalState @*/ - /*...@modifies ruby, *resultp, fileSystem, internalState @*/; +rpmruby rpmrubyNew(/*...@null@*/ char **av, uint32_t flags) + /*...@globals fileSystem, internalState @*/ + /*...@modifies fileSystem, internalState @*/; + + +/** + * Evaluates Ruby code stored in a string + * + * @param ruby The Ruby interpreter that is to be used + * (NULL uses global interpreter) + * @param str Ruby code to evaluate (NULL forces return of RPMRC_FAIL) + * @param *resultp Result of the evaluation + * @return RPMRC_OK on success + */ +rpmRC rpmrubyRun(rpmruby ruby, /*...@null@*/ const char *str, + /*...@null@*/ const char **resultp) + /*...@globals fileSystem, internalState @*/ + /*...@modifies ruby, *resultp, fileSystem, internalState @*/; + #ifdef __cplusplus } #endif #endif /* RPMRUBY_H */ + @@ . ______________________________________________________________________ RPM Package Manager http://rpm5.org CVS Sources Repository rpm-cvs@rpm5.org