rpm 5.3.12
rpmio/rpmruby.c
Go to the documentation of this file.
00001 #include "system.h"
00002 
00003 #if defined(WITH_RUBYEMBED)
00004 /* XXX ruby-1.8.6 grrr, ruby.h includes its own config.h too. */
00005 #ifdef  HAVE_CONFIG_H
00006 #include "config.h"
00007 #endif
00008 #undef  PACKAGE_NAME
00009 #undef  PACKAGE_TARNAME
00010 #undef  PACKAGE_VERSION
00011 #undef  PACKAGE_STRING
00012 #undef  PACKAGE_BUGREPORT
00013 
00014 #undef  xmalloc
00015 #undef  xcalloc
00016 #undef  xrealloc
00017 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
00018 #include <ruby.h>
00019 #pragma GCC diagnostic warning "-Wstrict-prototypes"
00020 
00021 #if !defined(RSTRING_PTR)
00022 /* XXX retrofit for ruby-1.8.5 in CentOS5 */
00023 #define RSTRING_PTR(s) (RSTRING(s)->ptr)
00024 #define RSTRING_LEN(s) (RSTRING(s)->len)
00025 #endif
00026 
00027 #endif
00028 
00029 #define _RPMRUBY_INTERNAL
00030 #include "rpmruby.h"
00031 
00032 #include "debug.h"
00033 
00034 /*@unchecked@*/
00035 int _rpmruby_debug = 0;
00036 
00037 /*@unchecked@*/ /*@relnull@*/
00038 rpmruby _rpmrubyI = NULL;
00039 
00040 /*==============================================================*/
00041 #if defined(HAVE_RUBY_DEFINES_H)        /* XXX ruby-1.9.2p0 */
00042 /* puts the Ruby coroutine in control */
00043 static void _rpmruby_main_to_ruby(rpmruby ruby)
00044 {
00045     rpmzLog zlog = ruby->zlog;
00046 
00047     yarnRelease(ruby->ruby_coroutine_lock);
00048     yarnPossess(ruby->main_coroutine_lock);
00049 if (_rpmruby_debug < 0) Trace((zlog, "-> %s", __FUNCTION__));
00050 }
00051 
00052 /* puts the main C program in control */
00053 static unsigned long _rpmruby_ruby_to_main(rpmruby ruby, unsigned long self)
00054 {
00055     rpmzLog zlog = ruby->zlog;
00056 
00057     yarnRelease(ruby->main_coroutine_lock);
00058     yarnPossess(ruby->ruby_coroutine_lock);
00059 if (_rpmruby_debug < 0) Trace((zlog, "<- %s", __FUNCTION__));
00060     return Qnil;
00061 }
00062 
00063 /* Using _rpmrubyI, puts the main C program in control */
00064 static VALUE relay_from_ruby_to_main(VALUE self)
00065 {
00066     /* XXX FIXME: _rpmrubyI is global */
00067     return _rpmruby_ruby_to_main(_rpmrubyI, self);
00068 }
00069 
00070 static rpmRC rpmrubyRunThreadFile(rpmruby ruby, const char * fn,
00071                 const char **resultp)
00072 {
00073     int error;
00074     VALUE result;
00075     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00076 
00077     result = rb_protect((VALUE (*)(VALUE))rb_require, (VALUE)fn, &error);
00078     if (error) {
00079         fprintf(stderr, "rb_require('%s') failed with status=%d\n",
00080                fn, error);
00081 
00082         VALUE exception = rb_gv_get("$!");
00083         if (RTEST(exception)) {
00084             fprintf(stderr, "... because an exception was raised:\n");
00085 
00086             VALUE inspect = rb_inspect(exception);
00087             rb_io_puts(1, &inspect, rb_stderr);
00088 
00089             VALUE backtrace = rb_funcall(
00090                 exception, rb_intern("backtrace"), 0);
00091             rb_io_puts(1, &backtrace, rb_stderr);
00092         }
00093     } else {
00094         /* XXX FIXME: check result */
00095         rc = RPMRC_OK;
00096     }
00097 
00098     return rc;
00099 }
00100 
00101 static void * rpmrubyThread(void * _ruby)
00102 {
00103     rpmruby ruby = _ruby;
00104     rpmzLog zlog = ruby->zlog;
00105     int i;
00106 
00107     Trace((zlog, "-- %s: running", __FUNCTION__));
00108 
00109     _rpmruby_ruby_to_main(ruby, Qnil);
00110 
00111     for (i = 0; i < 2; i++)
00112         _rpmruby_ruby_to_main(ruby, Qnil);
00113 
00114     {
00115         VALUE variable_in_this_stack_frame;
00116         uint8_t * b = ruby->stack;
00117         uint8_t * e = b + ruby->nstack;
00118 
00119         /* Start up the ruby interpreter. */
00120         Trace((zlog, "-- %s: interpreter starting", __FUNCTION__));
00121         ruby_sysinit(&ruby->ac, (char ***) &ruby->av);
00122 
00123         ruby_bind_stack((VALUE *)b, (VALUE *)e);
00124 
00125         ruby_init_stack(&variable_in_this_stack_frame);
00126         ruby_init();
00127         ruby_init_loadpath();
00128 
00129         /* allow Ruby script to relay */
00130         rb_define_module_function(rb_mKernel, "relay_from_ruby_to_main",
00131                                   relay_from_ruby_to_main, 0);
00132         Trace((zlog, "-- %s: interpreter started", __FUNCTION__));
00133 
00134         /* Run file.rb arguments. */
00135         for (i = 1; i < ruby->ac; i++) {
00136             if (*ruby->av[i] == '-')    /* XXX FIXME: skip options. */
00137                 continue;
00138             Trace((zlog, "-- %s: require '%s' begin", __FUNCTION__, ruby->av[i]));
00139             rpmrubyRunThreadFile(ruby, ruby->av[i], NULL);
00140             Trace((zlog, "-- %s: require '%s' end", __FUNCTION__, ruby->av[i]));
00141         }
00142 
00143         /* Terminate the ruby interpreter. */
00144         Trace((zlog, "-- %s: interpreter terminating", __FUNCTION__));
00145         ruby_finalize();
00146         ruby_cleanup(0);
00147         Trace((zlog, "-- %s: interpreter terminated", __FUNCTION__));
00148     }
00149 
00150     /* Report interpreter end to main. */
00151     ruby->more = 0;
00152     /* Permit main thread to run without blocking. */
00153     yarnRelease(ruby->main_coroutine_lock);
00154 
00155     Trace((zlog, "-- %s: ended", __FUNCTION__));
00156     return NULL;
00157 }
00158 #endif  /* HAVE_RUBY_DEFINES_H */
00159 
00160 int rpmrubyRunThread(rpmruby ruby)
00161 {
00162     int ec = 0;
00163 
00164 #if defined(HAVE_RUBY_DEFINES_H)        /* XXX ruby-1.9.2p0 */
00165     yarnPossess(ruby->ruby_coroutine_lock);
00166     yarnPossess(ruby->main_coroutine_lock);
00167 
00168     /* create a thread to house Ruby */
00169     ruby->thread = yarnLaunchStack((void (*)(void *))rpmrubyThread, ruby,
00170                                 ruby->stack, ruby->nstack);
00171 assert(ruby->thread != NULL);
00172 
00173     /* Relay control to ruby until nothing more to do. */
00174     ruby->more = (ruby->ac > 1);
00175     while (ruby->more)
00176         _rpmruby_main_to_ruby(ruby);
00177 
00178     /* Permit ruby thread to run without blocking. */
00179     yarnRelease(ruby->ruby_coroutine_lock);
00180     /* Reap the ruby thread. */
00181     ruby->thread = yarnJoin(ruby->thread);
00182     ec = 0;
00183 #endif  /* HAVE_RUBY_DEFINES_H */
00184 
00185     return ec;
00186 }
00187 
00188 /*==============================================================*/
00189 
00190 static void rpmrubyFini(void * _ruby)
00191         /*@globals fileSystem @*/
00192         /*@modifies *_ruby, fileSystem @*/
00193 {
00194     rpmruby ruby = _ruby;
00195 
00196     /* XXX FIXME: 0x40000000 => xruby.c wrapper without interpreter. */
00197     if (ruby->flags & 0x40000000) {
00198         ruby->main_coroutine_lock = yarnFreeLock(ruby->main_coroutine_lock);
00199         ruby->ruby_coroutine_lock = yarnFreeLock(ruby->ruby_coroutine_lock);
00200         ruby->zlog = rpmzLogDump(ruby->zlog, NULL);
00201         ruby->stack = _free(ruby->stack);
00202         ruby->nstack = 0;
00203         _rpmrubyI = NULL;
00204     } else {
00205 #if defined(WITH_RUBYEMBED)
00206         ruby_finalize();
00207         ruby_cleanup(0);
00208 #endif
00209     }
00210     ruby->I = NULL;
00211     ruby->flags = 0;
00212     ruby->av = argvFree(ruby->av);
00213     ruby->ac = 0;
00214 }
00215 
00216 /*@unchecked@*/ /*@only@*/ /*@null@*/
00217 rpmioPool _rpmrubyPool;
00218 
00219 static rpmruby rpmrubyGetPool(/*@null@*/ rpmioPool pool)
00220         /*@globals _rpmrubyPool, fileSystem @*/
00221         /*@modifies pool, _rpmrubyPool, fileSystem @*/
00222 {
00223     rpmruby ruby;
00224 
00225     if (_rpmrubyPool == NULL) {
00226         _rpmrubyPool = rpmioNewPool("ruby", sizeof(*ruby), -1, _rpmruby_debug,
00227                         NULL, NULL, rpmrubyFini);
00228         pool = _rpmrubyPool;
00229     }
00230     return (rpmruby) rpmioGetPool(pool, sizeof(*ruby));
00231 }
00232 
00233 /*@unchecked@*/
00234 #if defined(WITH_RUBYEMBED) && !defined(HAVE_RUBY_DEFINES_H)/* XXX ruby-1.8.6 */
00235 static const char * rpmrubyInitStringIO = "\
00236 require 'stringio'\n\
00237 $stdout = StringIO.new($result, \"w+\")\n\
00238 ";
00239 #endif
00240 
00241 static rpmruby rpmrubyI(void)
00242         /*@globals _rpmrubyI @*/
00243         /*@modifies _rpmrubyI @*/
00244 {
00245     /* XXX FIXME: pass 0x40000000 for wrapper without interpreter? */
00246     if (_rpmrubyI == NULL)
00247         _rpmrubyI = rpmrubyNew(NULL, 0);
00248 RUBYDBG((stderr, "<-- %s() I %p\n", __FUNCTION__, _rpmrubyI));
00249     return _rpmrubyI;
00250 }
00251 
00252 rpmruby rpmrubyNew(char ** av, uint32_t flags)
00253 {
00254     static char * _av[] = { "rpmruby", NULL };
00255     rpmruby ruby = (flags & 0x80000000)
00256                 ? rpmrubyI() : rpmrubyGetPool(_rpmrubyPool);
00257 int xx;
00258 
00259 RUBYDBG((stderr, "--> %s(%p,0x%x) ruby %p\n", __FUNCTION__, av, flags, ruby));
00260 
00261     /* If failure, or retrieving already initialized _rpmrubyI, just exit. */
00262     if (ruby == NULL || ruby == _rpmrubyI)
00263         goto exit;
00264 
00265     if (av == NULL) av = _av;
00266 
00267     ruby->flags = flags;
00268     xx = argvAppend(&ruby->av, (ARGV_t)av);
00269     ruby->ac = argvCount(ruby->av);
00270 
00271     /* XXX FIXME: 0x40000000 => xruby.c wrapper without interpreter. */
00272     if (ruby->flags & 0x40000000) {
00273         static size_t _rpmrubyStackSize = 4 * 1024 * 1024;
00274 
00275         /* XXX save as global interpreter. */
00276         _rpmrubyI = ruby;
00277 
00278         ruby->nstack = _rpmrubyStackSize;
00279         ruby->stack = malloc(ruby->nstack);
00280 assert(ruby->stack != NULL);
00281 
00282         gettimeofday(&ruby->start, NULL);  /* starting time for log entries */
00283         if (_rpmruby_debug)
00284             ruby->zlog = rpmzLogNew(&ruby->start);  /* initialize logging */
00285 
00286         /* initialize the relay mechanism */
00287         ruby->ruby_coroutine_lock = yarnNewLock(0);
00288         ruby->main_coroutine_lock = yarnNewLock(0);
00289 
00290     } else {
00291 
00292 #if defined(WITH_RUBYEMBED)
00293         VALUE variable_in_this_stack_frame;             /* RUBY_INIT_STSCK */
00294 
00295 #if defined(HAVE_RUBY_DEFINES_H)        /* XXX ruby-1.9.2 */
00296         ruby_sysinit(&ruby->ac, (char ***) &ruby->av);
00297         /* XXX ruby-1.9.2p0 ruby_bind_stack() patch needed */
00298         {
00299             uint8_t * b = ruby->stack;
00300             uint8_t * e = b + ruby->nstack;
00301             ruby_bind_stack((VALUE *)b, (VALUE *) e);
00302         }
00303 #endif  /* NOTYET */
00304 
00305         ruby_init_stack(&variable_in_this_stack_frame); /* RUBY_INIT_STACK */
00306 
00307         ruby_init();
00308         ruby_init_loadpath();
00309 
00310         ruby_script((char *)av[0]);
00311         if (av[1])
00312             ruby_set_argv(argvCount((ARGV_t)av)-1, av+1);
00313 
00314         rb_gv_set("$result", rb_str_new2(""));
00315 #if !defined(HAVE_RUBY_DEFINES_H)       /* XXX ruby-1.8.6 */
00316         (void) rpmrubyRun(ruby, rpmrubyInitStringIO, NULL);
00317 #endif
00318 #endif  /* WITH_RUBYEMBED */
00319     }
00320 
00321 exit:
00322     return rpmrubyLink(ruby);
00323 }
00324 
00325 rpmRC rpmrubyRunFile(rpmruby ruby, const char * fn, const char ** resultp)
00326 {
00327     rpmRC rc = RPMRC_FAIL;
00328 
00329 RUBYDBG((stderr, "--> %s(%p,%s,%p)\n", __FUNCTION__, ruby, fn, resultp));
00330 
00331     if (ruby == NULL) ruby = rpmrubyI();
00332 
00333     if (fn == NULL)
00334         goto exit;
00335 
00336 #if defined(WITH_RUBYEMBED)
00337 #if !defined(HAVE_RUBY_DEFINES_H)       /* XXX ruby-1.8.6 */
00338     rb_load_file(fn);
00339     ruby->state = ruby_exec();
00340 #else
00341     ruby->state = ruby_exec_node(rb_load_file(fn));
00342 #endif
00343     if (resultp != NULL)
00344         *resultp = RSTRING_PTR(rb_gv_get("$result"));
00345     rc = RPMRC_OK;
00346 #endif  /* WITH_RUBYEMBED */
00347 
00348 exit:
00349 RUBYDBG((stderr, "<-- %s(%p,%s,%p) rc %d\n", __FUNCTION__, ruby, fn, resultp, rc));
00350     return rc;
00351 }
00352 
00353 rpmRC rpmrubyRun(rpmruby ruby, const char * str, const char ** resultp)
00354 {
00355     rpmRC rc = RPMRC_FAIL;
00356 
00357 RUBYDBG((stderr, "--> %s(%p,%s,%p)\n", __FUNCTION__, ruby, str, resultp));
00358 
00359     if (ruby == NULL) ruby = rpmrubyI();
00360 
00361     if (str == NULL)
00362         goto exit;
00363 
00364 #if defined(WITH_RUBYEMBED)
00365     ruby->state = rb_eval_string(str);
00366     if (resultp != NULL)
00367         *resultp = RSTRING_PTR(rb_gv_get("$result"));
00368     rc = RPMRC_OK;
00369 #endif
00370 
00371 exit:
00372 RUBYDBG((stderr, "<-- %s(%p,%s,%p) rc %d\n", __FUNCTION__, ruby, str, resultp, rc));
00373     return rc;
00374 }