mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Imports Ruby's port to NativeClient (a.k.a NaCl).
Patch by Google Inc. [ruby-core:45073]. * configure.in (RUBY_NACL): New M4 func to configure variables for NaCl. (RUBY_NACL_CHECK_PEPPER_TYPES): New M4 func to check the old names of Pepper interface types. (BTESTRUBY): New variable to specify which ruby should be run on "make btest". NaCl can run the built binary by sel_ldr, but it need rbconfig.rb. So this variable is distinguished from $MINIRUBY. * thread_pthread.c: Disabled some features on NaCl. * io.c: ditto. * process.c: ditto. * signal.c: ditto. * file.c: ditto. * missing/flock.c: ditto. * nacl/pepper_main.c: An example implementation of Pepper application that embeds Ruby. * nacl/example.html: An example of web page that uses the Pepper application. * nacl/nacl-config.rb: Detects variants of NaCl SDK. * nacl/GNUmakefile.in: Makefile template for NaCl specific build process. * nacl/package.rb: script for packaging a NaCl-Ruby embedding application. * nacl/reate_nmf.rb: Wrapper script of create_nmf.py * dln.c (dln_load): Added a hack to call on NaCl. * util.c (ruby_getcwd): Path to the current directort is not available on NaCl. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35672 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
0a7aada5d1
commit
76bc2d1ed7
37 changed files with 1855 additions and 36 deletions
49
ChangeLog
49
ChangeLog
|
@ -1,6 +1,53 @@
|
|||
Thu May 17 11:33:07 2012 Yuki Yugui Sonoda <yugui@google.com>
|
||||
|
||||
Imports Ruby's port to NativeClient (a.k.a NaCl).
|
||||
Patch by Google Inc. [ruby-core:45073].
|
||||
|
||||
* configure.in (RUBY_NACL): New M4 func to configure variables for
|
||||
NaCl.
|
||||
(RUBY_NACL_CHECK_PEPPER_TYPES): New M4 func to check the old names
|
||||
of Pepper interface types.
|
||||
(BTESTRUBY): New variable to specify which ruby should be run on
|
||||
"make btest". NaCl can run the built binary by sel_ldr, but it need
|
||||
rbconfig.rb. So this variable is distinguished from $MINIRUBY.
|
||||
|
||||
* thread_pthread.c: Disabled some features on NaCl.
|
||||
|
||||
* io.c: ditto.
|
||||
|
||||
* process.c: ditto.
|
||||
|
||||
* signal.c: ditto.
|
||||
|
||||
* file.c: ditto.
|
||||
|
||||
* missing/flock.c: ditto.
|
||||
|
||||
* nacl/pepper_main.c: An example implementation of Pepper application
|
||||
that embeds Ruby.
|
||||
|
||||
* nacl/example.html: An example of web page that uses the Pepper
|
||||
application.
|
||||
|
||||
* nacl/nacl-config.rb: Detects variants of NaCl SDK.
|
||||
|
||||
* nacl/GNUmakefile.in: Makefile template for NaCl specific build
|
||||
process.
|
||||
|
||||
* nacl/package.rb: script for packaging a NaCl-Ruby embedding
|
||||
application.
|
||||
|
||||
* nacl/reate_nmf.rb: Wrapper script of create_nmf.py
|
||||
|
||||
* dln.c (dln_load): Added a hack to call on NaCl.
|
||||
|
||||
* util.c (ruby_getcwd): Path to the current directort is not available
|
||||
on NaCl.
|
||||
|
||||
Thu May 17 10:54:58 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* ext/tk/extconf.rb: add -l options to $libs not $LDFLAGS, to be
|
||||
* ext/tk/extconf.rb: add -l options to $libs not $LDFLAGS,
|
||||
to be
|
||||
passed to EXTLIBS in exts.mk.
|
||||
|
||||
* enc/encinit.c.erb: use %-lines to adjust indent in the generated file.
|
||||
|
|
|
@ -90,6 +90,8 @@ MINIRUBY = @MINIRUBY@\
|
|||
$(MINIRUBYOPT)
|
||||
RUNRUBY = @RUNRUBY@ $(RUNRUBYOPT) -- $(RUN_OPTS)
|
||||
XRUBY = @XRUBY@
|
||||
BTESTRUBY = @BTESTRUBY@\
|
||||
$(MINIRUBYOPT)
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
|
|
|
@ -472,7 +472,7 @@ check-ruby: test test-ruby
|
|||
btest: $(TEST_RUNNABLE)-btest
|
||||
no-btest: PHONY
|
||||
yes-btest: miniruby$(EXEEXT) PHONY
|
||||
$(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(MINIRUBY)" $(OPTS)
|
||||
$(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(BTESTRUBY)" $(OPTS)
|
||||
|
||||
btest-ruby: $(TEST_RUNNABLE)-btest-ruby
|
||||
no-btest-ruby: PHONY
|
||||
|
|
130
configure.in
130
configure.in
|
@ -51,6 +51,79 @@ target_cpu=x64
|
|||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([RUBY_NACL],
|
||||
[
|
||||
AS_CASE(["${host_os}"],
|
||||
[nacl], [
|
||||
ac_cv_exeext=.nexe
|
||||
host_vendor=chromium
|
||||
ac_cv_host=chromium
|
||||
AC_MSG_CHECKING([wheather \$NACL_SDK_ROOT is set])
|
||||
if test x"${NACL_SDK_ROOT}" = x; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([You need to set \$NACL_SDK_ROOT environment variable to build for NativeClient])
|
||||
fi
|
||||
AC_MSG_RESULT([yes])
|
||||
|
||||
nacl_cv_build_variant=glibc
|
||||
AC_ARG_WITH(newlib,
|
||||
AS_HELP_STRING([--with-newlib], [uses newlib version of NativeClient SDK]),
|
||||
[AS_CASE([$withval],
|
||||
[no], [nacl_cv_build_variant=glibc],
|
||||
[yes], [nacl_cv_build_variant=newlib])])
|
||||
|
||||
AS_CASE(["$build_cpu"],
|
||||
[x86_64|i?86], [nacl_cv_cpu_nick=x86], [nacl_cv_cpu_nick=$build_cpu])
|
||||
AS_CASE(["$build_os"],
|
||||
[linux*], [nacl_cv_os_nick=linux],
|
||||
[darwin*], [nacl_cv_os_nick=mac],
|
||||
[cygwin*|mingw*], [nacl_cv_os_nick=win],
|
||||
[nacl_cv_os_nick=$build_os])
|
||||
|
||||
host="$host_cpu-chromium-$host_os-"
|
||||
ac_tool_prefix="$host_cpu-nacl-"
|
||||
|
||||
AC_MSG_CHECKING([NativeClient toolchain])
|
||||
if test -d \
|
||||
"${NACL_SDK_ROOT}/toolchain/${nacl_cv_os_nick}_${nacl_cv_cpu_nick}_${nacl_cv_build_variant}"; then
|
||||
NACL_TOOLCHAIN="${nacl_cv_os_nick}_${nacl_cv_cpu_nick}_${nacl_cv_build_variant}"
|
||||
else
|
||||
AS_CASE(
|
||||
["${nacl_cv_build_variant}"],
|
||||
[glibc], [if test \
|
||||
-d "${NACL_SDK_ROOT}/toolchain/${nacl_cv_os_nick}_${nacl_cv_cpu_nick}_newlib" \
|
||||
-a -d "${NACL_SDK_ROOT}/toolchain/${nacl_cv_os_nick}_${nacl_cv_cpu_nick}"; then
|
||||
NACL_TOOLCHAIN="${nacl_cv_os_nick}_${nacl_cv_cpu_nick}"
|
||||
fi],
|
||||
[newlib], [ NACL_TOOLCHAIN="${nacl_cv_os_nick}_${nacl_cv_cpu_nick}" ])
|
||||
fi
|
||||
if test ! -e "${NACL_SDK_ROOT}/toolchain/${NACL_TOOLCHAIN}/${ac_tool_prefix}gcc"; then
|
||||
if test "${build_cpu}" = i686 -a -e "${NACL_SDK_ROOT}/toolchain/${NACL_TOOLCHAIN}/nacl-gcc"; then
|
||||
ac_tool_prefix=nacl-
|
||||
fi
|
||||
if test "${build_cpu}" = x86_64 -a -e "${NACL_SDK_ROOT}/toolchain/${NACL_TOOLCHAIN}/nacl-gcc"; then
|
||||
ac_tool_prefix=nacl64-
|
||||
fi
|
||||
fi
|
||||
if test -z "${NACL_TOOLCHAIN}"; then
|
||||
AC_MSG_ERROR([Unrecognized --host and --build combination or NaCl SDK is not installed])
|
||||
fi
|
||||
PATH="${PATH}:${NACL_SDK_ROOT}/toolchain/${NACL_TOOLCHAIN}/bin"
|
||||
AC_MSG_RESULT(${NACL_TOOLCHAIN})
|
||||
|
||||
AC_SUBST(NACL_TOOLCHAIN)
|
||||
AC_SUBST(NACL_SDK_ROOT)
|
||||
AC_SUBST(NACL_SDK_VARIANT, nacl_cv_build_variant)
|
||||
])])
|
||||
|
||||
AC_DEFUN([RUBY_NACL_CHECK_PEPPER_TYPES],
|
||||
[
|
||||
AC_CHECK_TYPES([struct PPB_Core, struct PPB_Messaging, struct PPB_Var,
|
||||
struct PPB_URLLoader, struct PPB_URLRequestInfo,
|
||||
struct PPB_URLResponseInfo, struct PPB_FileRef,
|
||||
struct PPP_Instance])
|
||||
])
|
||||
|
||||
AC_DEFUN([RUBY_CPPOUTFILE],
|
||||
[AC_CACHE_CHECK(whether ${CPP} accepts -o, rb_cv_cppoutfile,
|
||||
[cppflags=$CPPFLAGS
|
||||
|
@ -283,6 +356,7 @@ if test -z "${CXXFLAGS+set}"; then
|
|||
cxxflags="$cxxflags "'${optflags} ${debugflags} ${warnflags}'
|
||||
fi
|
||||
|
||||
RUBY_NACL
|
||||
if test x"${build}" != x"${host}"; then
|
||||
AC_CHECK_TOOL(CC, gcc)
|
||||
fi
|
||||
|
@ -377,6 +451,7 @@ AC_SUBST(MAKEDIRS)
|
|||
|
||||
AC_CHECK_PROGS(DOT, dot)
|
||||
AC_CHECK_PROGS(DOXYGEN, doxygen)
|
||||
AS_CASE(["${host_os}"], [nacl], [AC_PATH_PROG(PYTHON, python)])
|
||||
|
||||
AC_CHECK_PROG(PKG_CONFIG, pkg-config, [pkg-config], [], [],
|
||||
[`"$as_dir/$ac_word$ac_exec_ext" --print-errors --version > /dev/null 2>&1 || echo "$as_dir/$ac_word$ac_exec_ext"`])
|
||||
|
@ -509,7 +584,7 @@ if test "$GCC" = yes; then
|
|||
|
||||
# -fstack-protector
|
||||
AS_CASE(["$target_os"],
|
||||
[mingw*], [
|
||||
[mingw*|nacl], [
|
||||
stack_protector=no
|
||||
],
|
||||
[
|
||||
|
@ -1135,6 +1210,14 @@ main()
|
|||
],
|
||||
[superux*], [ ac_cv_func_setitimer=no
|
||||
],
|
||||
[nacl], [
|
||||
LIBS="-lm -lnosys $LIBS"
|
||||
if test "${nacl_cv_build_variant}" = "newlib"; then
|
||||
RUBY_APPEND_OPTION(CPPFLAGS, -DNACL_NEWLIB)
|
||||
else
|
||||
RUBY_APPEND_OPTION(XCFLAGS, -fPIC)
|
||||
fi
|
||||
],
|
||||
[ LIBS="-lm $LIBS"])
|
||||
AC_CHECK_LIB(crypt, crypt)
|
||||
AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV
|
||||
|
@ -1201,6 +1284,9 @@ AC_CHECK_MEMBERS([struct stat.st_ctimensec])
|
|||
|
||||
AC_CHECK_TYPES([struct timespec], [], [], [@%:@ifdef HAVE_TIME_H
|
||||
@%:@include <time.h>
|
||||
@%:@endif
|
||||
@%:@ifdef HAVE_SYS_TIME_H
|
||||
@%:@include <sys/time.h>
|
||||
@%:@endif])
|
||||
|
||||
AC_CHECK_TYPES([struct timezone], [], [], [@%:@ifdef HAVE_TIME_H
|
||||
|
@ -1263,6 +1349,8 @@ RUBY_DEFINT(intptr_t, void*)
|
|||
RUBY_DEFINT(uintptr_t, void*, unsigned)
|
||||
RUBY_DEFINT(ssize_t, size_t, [], [@%:@include <sys/types.h>]) dnl may differ from int, so not use AC_TYPE_SSIZE_T.
|
||||
|
||||
RUBY_NACL_CHECK_PEPPER_TYPES
|
||||
|
||||
AC_CACHE_CHECK(for stack end address, rb_cv_stack_end_address,
|
||||
[rb_cv_stack_end_address=no
|
||||
for addr in __libc_stack_end _SEND; do
|
||||
|
@ -1451,11 +1539,11 @@ AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall __syscall chroot ge
|
|||
getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\
|
||||
getpriority getrlimit setrlimit sysconf close getpwnam_r getgrnam_r\
|
||||
dlopen sigprocmask sigaction sigsetjmp _setjmp _longjmp\
|
||||
setsid telldir seekdir fchmod cosh sinh tanh log2 round\
|
||||
setsid telldir seekdir fchmod cosh sinh tanh log2 round llabs\
|
||||
setuid setgid daemon select_large_fdset setenv unsetenv\
|
||||
mktime timegm gmtime_r clock_gettime gettimeofday poll ppoll\
|
||||
pread sendfile shutdown sigaltstack dl_iterate_phdr\
|
||||
dup3 pipe2 posix_memalign memalign)
|
||||
dup3 pipe2 posix_memalign memalign ioctl)
|
||||
|
||||
AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,
|
||||
[AC_TRY_COMPILE([
|
||||
|
@ -1917,7 +2005,8 @@ if test x"$enable_pthread" = xyes; then
|
|||
pthread_getattr_np pthread_attr_get_np pthread_attr_getstack\
|
||||
pthread_get_stackaddr_np pthread_get_stacksize_np \
|
||||
thr_stksegment pthread_stackseg_np pthread_getthrds_np \
|
||||
pthread_condattr_setclock pthread_sigmask)
|
||||
pthread_cond_initialize pthread_condattr_setclock pthread_condattr_init \
|
||||
pthread_sigmask)
|
||||
fi
|
||||
if test x"$ac_cv_header_ucontext_h" = xyes; then
|
||||
if test x"$rb_with_pthread" = xyes; then
|
||||
|
@ -2034,11 +2123,14 @@ if test "$rb_cv_binary_elf" = yes; then
|
|||
if test "$with_dln_a_out" = yes; then
|
||||
AC_MSG_ERROR(dln_a_out does not work with ELF)
|
||||
fi
|
||||
AC_LIBOBJ([addr2line])
|
||||
AC_CHECK_HEADERS([elf.h elf_abi.h])
|
||||
if test $ac_cv_header_elf_h = yes -o $ac_cv_header_elf_abi_h = yes; then
|
||||
AC_LIBOBJ([addr2line])
|
||||
fi
|
||||
fi
|
||||
|
||||
AS_CASE(["$target_os"],
|
||||
[linux* | gnu* | k*bsd*-gnu | bsdi* | kopensolaris*-gnu], [
|
||||
[linux* | gnu* | k*bsd*-gnu | bsdi* | kopensolaris*-gnu | nacl], [
|
||||
if test "$rb_cv_binary_elf" = no; then
|
||||
with_dln_a_out=yes
|
||||
else
|
||||
|
@ -2218,6 +2310,7 @@ if test "$with_dln_a_out" != yes; then
|
|||
rb_cv_dlopen=yes],
|
||||
[os2-emx*], [ LDFLAGS="$LDFLAGS -Zomf"
|
||||
],
|
||||
[nacl], [ LDSHARED='$(CC) -shared' ],
|
||||
[ : ${LDSHARED='$(LD)'}])
|
||||
AC_MSG_RESULT($rb_cv_dlopen)
|
||||
fi
|
||||
|
@ -2342,6 +2435,9 @@ AS_CASE(["$target_os"],
|
|||
[*djgpp*], [
|
||||
setup=Setup.dj
|
||||
],
|
||||
[nacl], [
|
||||
setup=Setup.nacl
|
||||
],
|
||||
[
|
||||
setup=Setup
|
||||
])
|
||||
|
@ -2352,6 +2448,7 @@ if test "$prefix" = NONE; then
|
|||
prefix=$ac_default_prefix
|
||||
fi
|
||||
|
||||
BTESTRUBY='$(MINIRUBY)'
|
||||
if test x"$cross_compiling" = xyes; then
|
||||
test x"$MINIRUBY" = x && MINIRUBY="${RUBY-$BASERUBY} -I`pwd` "-r'$(arch)-fake'
|
||||
XRUBY_LIBDIR=`${RUBY-$BASERUBY} -rrbconfig -e ['puts RbConfig::CONFIG["libdir"]']`
|
||||
|
@ -2364,6 +2461,20 @@ if test x"$cross_compiling" = xyes; then
|
|||
RUNRUBY='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
|
||||
XRUBY='$(MINIRUBY)'
|
||||
TEST_RUNNABLE=no
|
||||
|
||||
if test "$host_os" = "nacl"; then
|
||||
if test "$build_cpu" = "$host_cpu" || test "${nacl_cv_cpu_nick}" = "x86" -a "$host_cpu" = "i686"; then
|
||||
nacl_cv_sel_ldr='`$(MINIRUBY) $(srcdir)/nacl/nacl-config.rb sel_ldr`'
|
||||
nacl_cv_irt_core='`$(MINIRUBY) $(srcdir)/nacl/nacl-config.rb irt_core`'
|
||||
nacl_cv_runnable_ld='`$(MINIRUBY) $(srcdir)/nacl/nacl-config.rb runnable_ld`'
|
||||
nacl_cv_host_lib='`$(MINIRUBY) $(srcdir)/nacl/nacl-config.rb host_lib`'
|
||||
TEST_RUNNABLE=yes
|
||||
BTESTRUBY="${nacl_cv_sel_ldr} -a -B ${nacl_cv_irt_core} -w 1:3 -w 2:4"
|
||||
BTESTRUBY="$BTESTRUBY -- ${nacl_cv_runnable_ld} --library-path ${nacl_cv_host_lib}"
|
||||
BTESTRUBY="$BTESTRUBY `pwd`/"'miniruby$(EXEEXT) -I`cd $(srcdir)/lib; pwd` -I.'
|
||||
BTESTRUBY="$BTESTRUBY"' -I$(EXTOUT)/common 3>&1 4>&2 1>/dev/null 2>/dev/null '
|
||||
fi
|
||||
fi
|
||||
else
|
||||
MINIRUBY='./miniruby$(EXEEXT) -I$(srcdir)/lib -I.'
|
||||
MINIRUBY="$MINIRUBY"' -I$(EXTOUT)/common'
|
||||
|
@ -2374,6 +2485,7 @@ else
|
|||
fi
|
||||
AC_SUBST(TEST_RUNNABLE)
|
||||
AC_SUBST(MINIRUBY)
|
||||
AC_SUBST(BTESTRUBY)
|
||||
AC_SUBST(PREP)
|
||||
AC_SUBST(RUNRUBY)
|
||||
AC_SUBST(XRUBY)
|
||||
|
@ -2600,6 +2712,7 @@ AC_CACHE_CHECK([for prefix of external symbols], rb_cv_symbol_prefix, [
|
|||
SYMBOL_PREFIX="$rb_cv_symbol_prefix"
|
||||
test "x$SYMBOL_PREFIX" = xNONE && SYMBOL_PREFIX=''
|
||||
MINIDLNOBJ=dmydln.o
|
||||
|
||||
AS_CASE(["$target_os"],
|
||||
[linux*], [
|
||||
],
|
||||
|
@ -2679,7 +2792,10 @@ AS_CASE(["$target_os"],
|
|||
AS_CASE(["$YACC"],[*yacc*], [
|
||||
XCFLAGS="$XCFLAGS -DYYMAXDEPTH=300"
|
||||
YACC="$YACC -Nl40000 -Nm40000"
|
||||
])])
|
||||
])],
|
||||
[nacl], [
|
||||
FIRSTMAKEFILE=GNUmakefile:nacl/GNUmakefile.in
|
||||
])
|
||||
MINIOBJS="$MINIDLNOBJ"
|
||||
|
||||
AS_CASE(["$THREAD_MODEL"],
|
||||
|
|
4
dir.c
4
dir.c
|
@ -44,6 +44,10 @@
|
|||
# include "win32/dir.h"
|
||||
# endif
|
||||
#endif
|
||||
#if defined(__native_client__) && defined(NACL_NEWLIB)
|
||||
# include "nacl/dirent.h"
|
||||
# include "nacl/stat.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
|
15
dln.c
15
dln.c
|
@ -1318,13 +1318,28 @@ dln_load(const char *file)
|
|||
# define RTLD_GLOBAL 0
|
||||
#endif
|
||||
|
||||
#ifdef __native_client__
|
||||
char* p, *orig;
|
||||
if (file[0] == '.' && file[1] == '/') file+=2;
|
||||
orig = strdup(file);
|
||||
for (p = file; *p; ++p) {
|
||||
if (*p == '/') *p = '_';
|
||||
}
|
||||
#endif
|
||||
/* Load file */
|
||||
if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
|
||||
#ifdef __native_client__
|
||||
free(orig);
|
||||
#endif
|
||||
error = dln_strerror();
|
||||
goto failed;
|
||||
}
|
||||
|
||||
init_fct = (void(*)())(VALUE)dlsym(handle, buf);
|
||||
#ifdef __native_client__
|
||||
strcpy(file, orig);
|
||||
free(orig);
|
||||
#endif
|
||||
#if defined __SYMBIAN32__
|
||||
if (init_fct == NULL) {
|
||||
init_fct = (void(*)())dlsym(handle, "1"); /* Some Symbian versions do not support symbol table in DLL, ordinal numbers only */
|
||||
|
|
50
ext/Setup.nacl
Normal file
50
ext/Setup.nacl
Normal file
|
@ -0,0 +1,50 @@
|
|||
# #option nodynamic
|
||||
#
|
||||
# #Win32API
|
||||
# bigdecimal
|
||||
# continuation
|
||||
# coverage
|
||||
# #curses
|
||||
# date
|
||||
# #dbm
|
||||
# digest/bubblebabble
|
||||
# digest
|
||||
# digest/md5
|
||||
# digest/rmd160
|
||||
# digest/sha1
|
||||
# digest/sha2
|
||||
# dl
|
||||
# dl/callback
|
||||
# #dl/win32
|
||||
# etc
|
||||
# fcntl
|
||||
# fiber
|
||||
# #fiddle
|
||||
# #gdbm
|
||||
# #iconv
|
||||
# io/console
|
||||
# io/nonblock
|
||||
# io/wait
|
||||
# #json
|
||||
# json/generator
|
||||
# json/parser
|
||||
# mathn/complex
|
||||
# mathn/rational
|
||||
# nkf
|
||||
# objspace
|
||||
# #openssl
|
||||
# pathname
|
||||
# #psych
|
||||
# #pty
|
||||
# racc/cparse
|
||||
# #readline
|
||||
# ripper
|
||||
# #sdbm
|
||||
# #socket
|
||||
# stringio
|
||||
# strscan
|
||||
# syck
|
||||
# #syslog
|
||||
# #tk
|
||||
# #tk/tkutil
|
||||
# #zlib
|
|
@ -530,7 +530,7 @@ unless $extlist.empty?
|
|||
list = $extlist.dup
|
||||
built = []
|
||||
while e = list.shift
|
||||
s,t,i,r = e
|
||||
s,t,i,r,os = e
|
||||
if r and !(r -= built).empty?
|
||||
l = list.size
|
||||
if (while l > 0; break true if r.include?(list[l-=1][1]) end)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'mkmf'
|
||||
|
||||
if /mswin|mingw|bccwin/ !~ RUBY_PLATFORM
|
||||
if /mswin|mingw|bccwin|nacl/ !~ RUBY_PLATFORM
|
||||
have_header("sys/stropts.h")
|
||||
have_func("setresuid")
|
||||
have_header("libutil.h")
|
||||
|
|
22
file.c
22
file.c
|
@ -60,6 +60,13 @@ int flock(int, int);
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(__native_client__) && defined(NACL_NEWLIB)
|
||||
# include "nacl/utime.h"
|
||||
# include "nacl/stat.h"
|
||||
# include "nacl/unistd.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
|
@ -3358,7 +3365,11 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE l
|
|||
struct stat sbuf;
|
||||
int ret;
|
||||
VALUE testpath2 = rb_str_encode_ospath(testpath);
|
||||
#ifdef __native_client__
|
||||
ret = stat(RSTRING_PTR(testpath2), &sbuf);
|
||||
#else
|
||||
ret = lstat(RSTRING_PTR(testpath2), &sbuf);
|
||||
#endif
|
||||
if (ret == -1) {
|
||||
if (errno == ENOENT) {
|
||||
if (strict || !last || *unresolved_firstsep)
|
||||
|
@ -3403,6 +3414,13 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE l
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef __native_client__
|
||||
VALUE
|
||||
rb_realpath_internal(VALUE basedir, VALUE path, int strict)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
#else
|
||||
VALUE
|
||||
rb_realpath_internal(VALUE basedir, VALUE path, int strict)
|
||||
{
|
||||
|
@ -3476,6 +3494,7 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict)
|
|||
OBJ_TAINT(resolved);
|
||||
return resolved;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
|
@ -5142,6 +5161,9 @@ rb_path_check(const char *path)
|
|||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef __native_client__
|
||||
__attribute__((noinline))
|
||||
#endif
|
||||
int
|
||||
rb_file_load_ok(const char *path)
|
||||
{
|
||||
|
|
6
gc.c
6
gc.c
|
@ -32,6 +32,12 @@
|
|||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#if defined(__native_client__) && defined(NACL_NEWLIB)
|
||||
# include "nacl/resource.h"
|
||||
# undef HAVE_POSIX_MEMALIGN
|
||||
# undef HAVE_MEMALIGN
|
||||
|
||||
#endif
|
||||
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
|
|
4
gc.h
4
gc.h
|
@ -2,9 +2,9 @@
|
|||
#ifndef RUBY_GC_H
|
||||
#define RUBY_GC_H 1
|
||||
|
||||
#if defined(__x86_64__) && defined(__GNUC__)
|
||||
#if defined(__x86_64__) && defined(__GNUC__) && !defined(__native_client__)
|
||||
#define SET_MACHINE_STACK_END(p) __asm__("movq\t%%rsp, %0" : "=r" (*(p)))
|
||||
#elif defined(__i386) && defined(__GNUC__)
|
||||
#elif defined(__i386) && defined(__GNUC__) && !defined(__native_client__)
|
||||
#define SET_MACHINE_STACK_END(p) __asm__("movl\t%%esp, %0" : "=r" (*(p)))
|
||||
#else
|
||||
NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
|
||||
|
|
30
io.c
30
io.c
|
@ -28,7 +28,9 @@
|
|||
#if defined HAVE_NET_SOCKET_H
|
||||
# include <net/socket.h>
|
||||
#elif defined HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
# ifndef __native_client__
|
||||
# include <sys/socket.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32) || defined(__EMX__) || defined(__BEOS__) || defined(__HAIKU__)
|
||||
|
@ -47,6 +49,9 @@
|
|||
#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#if defined(__native_client__) && defined(NACL_NEWLIB)
|
||||
# include "nacl/ioctl.h"
|
||||
#endif
|
||||
#if defined(HAVE_FCNTL_H) || defined(_WIN32)
|
||||
#include <fcntl.h>
|
||||
#elif defined(HAVE_SYS_FCNTL_H)
|
||||
|
@ -161,7 +166,7 @@ void
|
|||
rb_maygvl_fd_fix_cloexec(int fd)
|
||||
{
|
||||
/* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
|
||||
#ifdef F_GETFD
|
||||
#if defined(F_GETFD) && !defined(__native_client__)
|
||||
int flags, flags2, ret;
|
||||
flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
|
||||
if (flags == -1) {
|
||||
|
@ -187,7 +192,6 @@ rb_fd_fix_cloexec(int fd)
|
|||
if (max_file_descriptor < fd) max_file_descriptor = fd;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rb_cloexec_open(const char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
|
@ -1502,6 +1506,7 @@ rb_io_set_pos(VALUE io, VALUE offset)
|
|||
|
||||
static void clear_readconv(rb_io_t *fptr);
|
||||
|
||||
#if defined(HAVE_FSYNC) || !defined(_WIN32)
|
||||
/*
|
||||
* call-seq:
|
||||
* ios.rewind -> 0
|
||||
|
@ -1540,6 +1545,7 @@ rb_io_rewind(VALUE io)
|
|||
|
||||
return INT2FIX(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
io_fillbuf(rb_io_t *fptr)
|
||||
|
@ -1629,6 +1635,7 @@ rb_io_eof(VALUE io)
|
|||
return Qfalse;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FSYNC
|
||||
/*
|
||||
* call-seq:
|
||||
* ios.sync -> true or false
|
||||
|
@ -1683,8 +1690,6 @@ rb_io_set_sync(VALUE io, VALUE sync)
|
|||
return sync;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FSYNC
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ios.fsync -> 0 or nil
|
||||
|
@ -1709,14 +1714,19 @@ rb_io_fsync(VALUE io)
|
|||
|
||||
if (io_fflush(fptr) < 0)
|
||||
rb_sys_fail(0);
|
||||
#ifndef _WIN32 /* already called in io_fflush() */
|
||||
# ifndef _WIN32 /* already called in io_fflush() */
|
||||
if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
|
||||
rb_sys_fail_path(fptr->pathv);
|
||||
#endif
|
||||
# endif
|
||||
return INT2FIX(0);
|
||||
}
|
||||
#else
|
||||
#define rb_io_fsync rb_f_notimplement
|
||||
# define rb_io_fsync rb_f_notimplement
|
||||
# define rb_io_sync rb_f_notimplement
|
||||
static VALUE rb_io_set_sync(VALUE io, VALUE sync) {
|
||||
rb_notimplement();
|
||||
/* NEVER REACHED */ return Qundef;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FDATASYNC
|
||||
|
@ -8200,10 +8210,10 @@ rb_f_select(int argc, VALUE *argv, VALUE obj)
|
|||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||
typedef unsigned long ioctl_req_t;
|
||||
#define NUM2IOCTLREQ(num) NUM2ULONG(num)
|
||||
# define NUM2IOCTLREQ(num) NUM2ULONG(num)
|
||||
#else
|
||||
typedef int ioctl_req_t;
|
||||
#define NUM2IOCTLREQ(num) NUM2INT(num)
|
||||
# define NUM2IOCTLREQ(num) NUM2INT(num)
|
||||
#endif
|
||||
|
||||
struct ioctl_arg {
|
||||
|
|
1
iseq.c
1
iseq.c
|
@ -1548,4 +1548,3 @@ Init_ISeq(void)
|
|||
rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1);
|
||||
rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "ruby/config.h"
|
||||
#include "ruby/ruby.h"
|
||||
|
||||
#if defined _WIN32
|
||||
#elif defined HAVE_FCNTL && defined HAVE_FCNTL_H
|
||||
#elif defined HAVE_FCNTL && defined HAVE_FCNTL_H && !defined(__native_client__)
|
||||
|
||||
/* These are the flock() constants. Since this sytems doesn't have
|
||||
flock(), the values of the constants are probably not available.
|
||||
|
|
60
nacl/GNUmakefile.in
Normal file
60
nacl/GNUmakefile.in
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Copyright 2012 Google Inc. All Rights Reserved.
|
||||
# Author: yugui@google.com (Yugui Sonoda)
|
||||
|
||||
include Makefile
|
||||
-include uncommon.mk
|
||||
|
||||
NACL_SDK_ROOT=@NACL_SDK_ROOT@
|
||||
NACL_TOOLCHAIN=@NACL_TOOLCHAIN@
|
||||
NACL_TOOLCHAIN_DIR=$(NACL_SDK_ROOT)/toolchain/$(NACL_TOOLCHAIN)
|
||||
PATH+=:$(NACL_TOOLCHAIN_DIR)/bin
|
||||
PYTHON=@PYTHON@
|
||||
|
||||
PPROGRAM=pepper-$(PROGRAM)
|
||||
PEPPER_LIBS=-lppapi
|
||||
PROGRAM_NMF=$(PROGRAM:.nexe=.nmf)
|
||||
PPROGRAM_NMF=$(PPROGRAM:.nexe=.nmf)
|
||||
|
||||
GNUmakefile: $(srcdir)/nacl/GNUmakefile.in
|
||||
$(PPROGRAM): $(PROGRAM) pepper_main.$(OBJEXT)
|
||||
$(Q)$(MAKE) $(MFLAGS) PROGRAM=$(PPROGRAM) MAINOBJ="pepper_main.$(OBJEXT)" LIBS="$(LIBS) $(PEPPER_LIBS)" program
|
||||
$(PROGRAM_NMF) $(PPROGRAM_NMF): $(@:.nmf=.nexe) nacl/create_nmf.rb
|
||||
|
||||
.PHONY: pprogram package show_naclflags
|
||||
.SUFFIXES: .nexe .nmf
|
||||
.nexe.nmf:
|
||||
$(ECHO) generating manifest $@
|
||||
$(Q)$(MINIRUBY) $(srcdir)/nacl/create_nmf.rb --verbose=$(V) $(@:.nmf=.nexe) $@
|
||||
|
||||
pepper_main.$(OBJEXT): $(srcdir)/nacl/pepper_main.c
|
||||
@$(ECHO) compiling nacl/pepper_main.c
|
||||
$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -c $(srcdir)/nacl/pepper_main.c
|
||||
ruby.$(OBJEXT):
|
||||
@$(ECHO) compiling $<
|
||||
$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@.tmp -c $<
|
||||
$(Q) $(OBJCOPY) --weaken-symbol=rb_load_file $@.tmp $@
|
||||
@-$(RM) $@.tmp
|
||||
file.$(OBJEXT):
|
||||
@$(ECHO) compiling $<
|
||||
$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@.tmp -c $<
|
||||
$(Q) $(OBJCOPY) --weaken-symbol=rb_file_load_ok $@.tmp $@
|
||||
@-$(RM) $@.tmp
|
||||
|
||||
all: pprogram
|
||||
main: $(PROGRAM_NMF)
|
||||
pprogram: showflags $(PPROGRAM) $(PPROGRAM_NMF)
|
||||
program: $(PROGRAM_NMF)
|
||||
prog: pprogram
|
||||
|
||||
package: pprogram install-lib install-ext-comm install-ext-arch
|
||||
$(ECHO) generating manifest $@
|
||||
$(Q)$(MINIRUBY) $(srcdir)/nacl/package.rb $(prefix)
|
||||
|
||||
showflags: show_naclflags
|
||||
|
||||
show_naclflags:
|
||||
@echo " PATH = $(PATH)"
|
||||
@echo " NACL_SDK_ROOT = $(NACL_SDK_ROOT)"
|
||||
|
||||
clean-local::
|
||||
-$(RM) $(PPROGRAM) pepper_main.$(OBJEXT) $(PROGRAM_NMF) $(PPRGORAM_NMF)
|
34
nacl/README.nacl
Normal file
34
nacl/README.nacl
Normal file
|
@ -0,0 +1,34 @@
|
|||
=begin
|
||||
= Native Client port of Ruby
|
||||
|
||||
= How to build
|
||||
== Prerequisites
|
||||
You need to install the following things before building NaCl port of Ruby.
|
||||
* Ruby 1.9.3 or later
|
||||
* Python 2.6 or later
|
||||
* NativeClient SDK pepper 18 or later
|
||||
* GNU make
|
||||
|
||||
== Steps
|
||||
(1) Extract all files from the tarball:
|
||||
$ tar xzf ruby-X.Y.Z.tar.gz
|
||||
(2) Set NACL_SDK_ROOT environment vairanble to the path to the Native Client SDK you installed:
|
||||
$ export NACL_SDK_ROOT=/home/yugui/src/nacl_sdk/pepper_16
|
||||
(3) Configure
|
||||
$ ./configure --prefix=/tmp/nacl-ruby --host=x86_64-nacl --with-baseruby=/path/to/ruby-1.9.3
|
||||
(4) Make
|
||||
$ make
|
||||
$ make package
|
||||
|
||||
Now you have ruby.nexe. You can run it by sel_ldr in NaCl SDK.
|
||||
|
||||
"make package" installs "pepper-ruby.nexe", an example Pepper application that
|
||||
embeds Ruby", and libraries to $prefix. You can run it by the following steps:
|
||||
(5) Publish the $prefix directory on a web server
|
||||
(6) Visit the example.html on the web server by a browser that implements Pepper 18 or later.
|
||||
-- e.g., Chrome 18 implements Pepper 18, Chrome 19 implements Pepper 19, ...
|
||||
|
||||
= Copyright
|
||||
* Copyright 2012 Google Inc. All Rights Reserved.
|
||||
* Author: yugui@google.com (Yugui Sonoda)
|
||||
=end
|
70
nacl/create_nmf.rb
Normal file
70
nacl/create_nmf.rb
Normal file
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/ruby
|
||||
# Copyright:: Copyright 2012 Google Inc.
|
||||
# License:: All Rights Reserved.
|
||||
# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
|
||||
#
|
||||
# Wrapper for create_nmf.py / generate_nmf.py
|
||||
|
||||
require File.join(File.dirname(__FILE__), 'nacl-config')
|
||||
|
||||
include NaClConfig
|
||||
$verbosity = 0
|
||||
|
||||
def usage_and_exit
|
||||
$stderr.puts "Usage: #{$PROGRAM_NAME} [--verbose=N] path/to/input.nexe path/to/output.nmf"
|
||||
exit false
|
||||
end
|
||||
|
||||
def create_dynamically_linked(nmf, exe)
|
||||
cmd = [
|
||||
PYTHON, CREATE_NMF,
|
||||
'-o', nmf,
|
||||
'-D', OBJDUMP,
|
||||
'-L', HOST_LIB,
|
||||
exe
|
||||
]
|
||||
puts cmd.join(' ') if $verbosity > 0
|
||||
exec(*cmd)
|
||||
end
|
||||
|
||||
def create_statically_linked(nmf, exe)
|
||||
File.open(nmf, "w") {|f|
|
||||
f.write <<-EOS.gsub(/^ {6}/, '')
|
||||
{
|
||||
"program": {
|
||||
"#{ARCH}": {
|
||||
"url": "#{exe}"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOS
|
||||
}
|
||||
end
|
||||
|
||||
def main
|
||||
while m = ARGV.first.match(/--([a-z-]+)(?:=(\S+))?/)
|
||||
case m[1]
|
||||
when 'verbose'
|
||||
usage_and_exit unless m[2][/\A[0-9]+\z/]
|
||||
$verbosity = m[2].to_i
|
||||
when 'help'
|
||||
usage_end_exit
|
||||
end
|
||||
ARGV.shift
|
||||
end
|
||||
|
||||
usage_and_exit if ARGV.size < 2
|
||||
|
||||
exe, nmf = ARGV[0], ARGV[1]
|
||||
if newlib?
|
||||
create_statically_linked(nmf, exe)
|
||||
else
|
||||
create_dynamically_linked(nmf, exe)
|
||||
end
|
||||
end
|
||||
|
||||
if __FILE__ == $0
|
||||
main()
|
||||
end
|
||||
|
||||
|
15
nacl/dirent.h
Normal file
15
nacl/dirent.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc. All Rights Reserved.
|
||||
* Author: yugui@google.com (Yugui Sonoda)
|
||||
*/
|
||||
#ifndef RUBY_NACL_DIRENT_H
|
||||
#define RUBY_NACL_DIRENT_H
|
||||
|
||||
/* NaCl SDK 0.3 has implementations of dir functions but no declaration in
|
||||
* dirent.h */
|
||||
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
|
||||
void rewinddir(DIR *dirp);
|
||||
long telldir(DIR *dirp);
|
||||
void seekdir(DIR *dirp, long offset);
|
||||
|
||||
#endif
|
150
nacl/example.html
Normal file
150
nacl/example.html
Normal file
|
@ -0,0 +1,150 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ruby Example</title>
|
||||
|
||||
<script type="text/javascript">
|
||||
RubyModule = null; // Global application object.
|
||||
statusText = 'NO-STATUS';
|
||||
rubyReady = false;
|
||||
|
||||
// Indicate load success.
|
||||
function moduleDidLoad() {
|
||||
RubyModule = document.getElementById('ruby');
|
||||
form = document.getElementById('source-form');
|
||||
form.style.display = "block";
|
||||
updateStatus('SUCCESS');
|
||||
}
|
||||
|
||||
function evalSource() {
|
||||
if (rubyReady) {
|
||||
RubyModule.postMessage('eval:' + document.getElementById("source").value);
|
||||
} else {
|
||||
throw "Not yet ready";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function RubyError(message) {
|
||||
this.message = message;
|
||||
this.toString = function() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
function FatalError(message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
// The 'message' event handler. This handler is fired when the NaCl module
|
||||
// posts a message to the browser by calling PPB_Messaging.PostMessage()
|
||||
// (in C) or pp::Instance.PostMessage() (in C++). This implementation
|
||||
// simply displays the content of the message in an alert panel.
|
||||
function handleMessage(message_event) {
|
||||
var raw = message_event.data;
|
||||
var components;
|
||||
if (raw.indexOf("error") == 0) {
|
||||
components = raw.split(":", 2);
|
||||
throw new RubyError(components[1]);
|
||||
} else if (raw.indexOf("return") == 0) {
|
||||
components = raw.split(":", 2);
|
||||
document.getElementById("result").value = components[1];
|
||||
} else if (raw == "rubyReady") {
|
||||
rubyReady = true;
|
||||
} else {
|
||||
throw new FatalError(raw);
|
||||
}
|
||||
}
|
||||
|
||||
// If the page loads before the Native Client module loads, then set the
|
||||
// status message indicating that the module is still loading. Otherwise,
|
||||
// do not change the status message.
|
||||
function pageDidLoad() {
|
||||
if (RubyModule == null) {
|
||||
updateStatus('LOADING...');
|
||||
} else {
|
||||
// It's possible that the Native Client module onload event fired
|
||||
// before the page's onload event. In this case, the status message
|
||||
// will reflect 'SUCCESS', but won't be displayed. This call will
|
||||
// display the current message.
|
||||
updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the global status message. If the element with id 'statusField'
|
||||
// exists, then set its HTML to the status message as well.
|
||||
// opt_message The message test. If this is null or undefined, then
|
||||
// attempt to set the element with id 'statusField' to the value of
|
||||
// |statusText|.
|
||||
function updateStatus(opt_message) {
|
||||
if (opt_message)
|
||||
statusText = opt_message;
|
||||
var statusField = document.getElementById('status_field');
|
||||
if (statusField) {
|
||||
statusField.innerHTML = statusText;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="pageDidLoad()">
|
||||
|
||||
<h1>Native Client Module Ruby</h1>
|
||||
<p>
|
||||
<!-- Load the published .nexe. This includes the 'nacl' attribute which
|
||||
shows how to load multi-architecture modules. Each entry in the "nexes"
|
||||
object in the .nmf manifest file is a key-value pair: the key is the
|
||||
instruction set architecture ('x86-32', 'x86-64', etc.); the value is a URL
|
||||
for the desired NaCl module.
|
||||
To load the debug versions of your .nexes, set the 'nacl' attribute to the
|
||||
_dbg.nmf version of the manifest file.
|
||||
|
||||
Note: Since this NaCl module does not use any real-estate in the browser,
|
||||
it's width and height are set to 0.
|
||||
|
||||
Note: The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
|
||||
and a 'message' event listener attached. This wrapping method is used
|
||||
instead of attaching the event listeners directly to the <EMBED> element to
|
||||
ensure that the listeners are active before the NaCl module 'load' event
|
||||
fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or
|
||||
pp::Instance.PostMessage() (in C++) from within the initialization code in
|
||||
your NaCl module.
|
||||
-->
|
||||
<div id="listener">
|
||||
<script type="text/javascript">
|
||||
var listener = document.getElementById('listener');
|
||||
listener.addEventListener('load', moduleDidLoad, true);
|
||||
listener.addEventListener('message', handleMessage, true);
|
||||
</script>
|
||||
|
||||
<embed name="nacl_module"
|
||||
id="ruby"
|
||||
width="0" height="0"
|
||||
src="ruby.nmf"
|
||||
type="application/x-nacl" />
|
||||
<form id="source-form" action="#" method="post" style="display:none"
|
||||
onsubmit="evalSource(); return false">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Source</th>
|
||||
<td>
|
||||
<textarea rows="10" cols="80" id="source"></textarea>
|
||||
<input type="submit" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Result</th>
|
||||
<td>
|
||||
<textarea rows="10" cols="80" id="result"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<h2>Status</h2>
|
||||
<div id="status_field">NO-STATUS</div>
|
||||
</body>
|
||||
</html>
|
7
nacl/ioctl.h
Normal file
7
nacl/ioctl.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
// Author: yugui@google.com (Yugui Sonoda)
|
||||
#ifndef RUBY_NACL_IOCTL_H
|
||||
#define RUBY_NACL_IOCTL_H
|
||||
int ioctl(int fd, int request, ...);
|
||||
struct flock{};
|
||||
#endif
|
61
nacl/nacl-config.rb
Normal file
61
nacl/nacl-config.rb
Normal file
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/ruby
|
||||
#
|
||||
# Copyright:: Copyright 2012 Google Inc.
|
||||
# License:: All Rights Reserved.
|
||||
# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
|
||||
#
|
||||
# Convenient functions/constants for native client specific configurations.
|
||||
require 'rbconfig'
|
||||
|
||||
module NaClConfig
|
||||
config = RbConfig::CONFIG
|
||||
|
||||
cpu_nick = config['host_alias'].sub(/-gnu$|-newlib$/, '').sub(/-nacl$/, '')
|
||||
ARCH = cpu_nick.sub('x86_64', 'x86-64').sub(/i.86/, 'x86-32')
|
||||
HOST = ARCH.sub(/x86-../, 'x86_64') + '-nacl'
|
||||
|
||||
lib_suffix = config['host_cpu'][/i.86/] ? '32' : ''
|
||||
PYTHON = config['PYTHON']
|
||||
OBJDUMP = config['OBJDUMP']
|
||||
SDK_ROOT = config['NACL_SDK_ROOT']
|
||||
CREATE_NMF = [
|
||||
File.join(SDK_ROOT, 'build_tools', 'nacl_sdk_scons', 'site_tools', 'create_nmf.py'),
|
||||
File.join(SDK_ROOT, 'tools', 'create_nmf.py')
|
||||
].find{|path| File.exist?(path) }
|
||||
HOST_LIB = File.join(SDK_ROOT, 'toolchain', config['NACL_TOOLCHAIN'], HOST, "lib#{lib_suffix}")
|
||||
|
||||
INSTALL_PROGRAM = config['INSTALL_PROGRAM']
|
||||
INSTALL_LIBRARY = config['INSTALL_DATA']
|
||||
|
||||
SEL_LDR = [
|
||||
File.join(SDK_ROOT, 'toolchain', config['NACL_TOOLCHAIN'], 'bin', "sel_ldr_#{cpu_nick}"),
|
||||
File.join(SDK_ROOT, 'tools', "sel_ldr_#{cpu_nick}")
|
||||
].find{|path| File.executable?(path)}
|
||||
IRT_CORE = [
|
||||
File.join(SDK_ROOT, 'toolchain', config['NACL_TOOLCHAIN'], 'bin', "irt_core_#{cpu_nick}.nexe"),
|
||||
File.join(SDK_ROOT, 'tools', "irt_core_#{cpu_nick}.nexe")
|
||||
].find{|path| File.executable?(path)}
|
||||
RUNNABLE_LD = File.join(HOST_LIB, 'runnable-ld.so')
|
||||
|
||||
module_function
|
||||
|
||||
def newlib?
|
||||
RbConfig::CONFIG['NACL_SDK_VARIANT'] == 'newlib'
|
||||
end
|
||||
|
||||
def self.config(name)
|
||||
if NaClConfig::const_defined?(name.upcase)
|
||||
NaClConfig::const_get(name.upcase)
|
||||
elsif NaClConfig::respond_to?(name) and NaClConfig::method(name).arity == 0
|
||||
NaClConfig::send(name)
|
||||
else
|
||||
raise ArgumentError, "No such config: #{name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
ARGV.each do |arg|
|
||||
puts NaClConfig::config(arg)
|
||||
end
|
||||
end
|
109
nacl/package.rb
Normal file
109
nacl/package.rb
Normal file
|
@ -0,0 +1,109 @@
|
|||
#!/usr/bin/ruby
|
||||
# Copyright:: Copyright 2012 Google Inc.
|
||||
# License:: All Rights Reserved.
|
||||
# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
|
||||
#
|
||||
# Generates a runnable package of the pepper API example.
|
||||
|
||||
require File.join(File.dirname(__FILE__), 'nacl-config')
|
||||
require 'json'
|
||||
require 'find'
|
||||
require 'fileutils'
|
||||
|
||||
include NaClConfig
|
||||
|
||||
class Installation
|
||||
include NaClConfig
|
||||
|
||||
SRC_DIRS = [ Dir.pwd, HOST_LIB ]
|
||||
|
||||
def initialize(destdir)
|
||||
@destdir = destdir
|
||||
@manifest = {
|
||||
"files" => {}
|
||||
}
|
||||
ruby_libs.each do |path|
|
||||
raise "Collision of #{path}" if @manifest['files'].key? path
|
||||
@manifest['files'][path] = {
|
||||
ARCH => {
|
||||
"url" => path
|
||||
}
|
||||
}
|
||||
if path[/\.so$/]
|
||||
alternate_path = path.gsub('/', "_")
|
||||
raise "Collision of #{alternate_path}" if @manifest['files'].key? alternate_path
|
||||
@manifest['files'][alternate_path] = {
|
||||
ARCH => {
|
||||
"url" => path
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def manifest
|
||||
@manifest.dup
|
||||
end
|
||||
|
||||
def install_program(basename)
|
||||
do_install_binary(basename, File.join(@destdir, "bin", ARCH))
|
||||
@manifest["program"] = {
|
||||
ARCH => {
|
||||
"url" => File.join("bin", ARCH, basename)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def install_library(name, basename)
|
||||
do_install_binary(basename, File.join(@destdir, "lib", ARCH))
|
||||
@manifest["files"][name] = {
|
||||
ARCH => {
|
||||
"url" => File.join("lib", ARCH, basename)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
def do_install_binary(basename, dest_dir)
|
||||
full_path = nil
|
||||
catch(:found) {
|
||||
SRC_DIRS.each do |path|
|
||||
full_path = File.join(path, basename)
|
||||
if File.exist? full_path
|
||||
throw :found
|
||||
end
|
||||
end
|
||||
raise Errno::ENOENT, "No such file to install: %s" % basename
|
||||
}
|
||||
FileUtils.mkdir_p dest_dir
|
||||
system("#{INSTALL_PROGRAM} #{full_path} #{dest_dir}")
|
||||
end
|
||||
|
||||
def ruby_libs
|
||||
Find.find(RbConfig::CONFIG['rubylibdir']).select{|path| File.file?(path) }.map{|path| path.sub("#{@destdir}/", "") }
|
||||
end
|
||||
end
|
||||
|
||||
def install(destdir)
|
||||
inst = Installation.new(destdir)
|
||||
manifest = JSON.parse(File.read("pepper-ruby.nmf"))
|
||||
|
||||
program = File.basename(manifest['program'][ARCH]['url'])
|
||||
inst.install_program(program)
|
||||
|
||||
manifest['files'].each do |name, attr|
|
||||
inst.install_library(name, File.basename(attr[ARCH]["url"]))
|
||||
end
|
||||
|
||||
File.open(File.join(destdir, "ruby.nmf"), "w") {|f|
|
||||
f.puts JSON.pretty_generate(inst.manifest)
|
||||
}
|
||||
end
|
||||
|
||||
def main
|
||||
install(ARGV[0])
|
||||
end
|
||||
|
||||
if __FILE__ == $0
|
||||
main()
|
||||
end
|
924
nacl/pepper_main.c
Normal file
924
nacl/pepper_main.c
Normal file
|
@ -0,0 +1,924 @@
|
|||
/******************************************************************************
|
||||
Copyright 2012 Google Inc. All Rights Reserved.
|
||||
Author: yugui@google.com (Yugui Sonoda)
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include "ppapi/c/pp_errors.h"
|
||||
#include "ppapi/c/pp_module.h"
|
||||
#include "ppapi/c/pp_var.h"
|
||||
#include "ppapi/c/ppb.h"
|
||||
#include "ppapi/c/ppb_core.h"
|
||||
#include "ppapi/c/ppb_file_ref.h"
|
||||
#include "ppapi/c/ppb_instance.h"
|
||||
#include "ppapi/c/ppb_messaging.h"
|
||||
#include "ppapi/c/ppb_url_loader.h"
|
||||
#include "ppapi/c/ppb_url_request_info.h"
|
||||
#include "ppapi/c/ppb_url_response_info.h"
|
||||
#include "ppapi/c/ppb_var.h"
|
||||
#include "ppapi/c/ppp.h"
|
||||
#include "ppapi/c/ppp_instance.h"
|
||||
#include "ppapi/c/ppp_messaging.h"
|
||||
|
||||
#include "ruby/ruby.h"
|
||||
#include "vm_core.h"
|
||||
#include "eval_intern.h"
|
||||
#include "gc.h"
|
||||
#include "node.h"
|
||||
|
||||
RUBY_GLOBAL_SETUP
|
||||
|
||||
#ifdef HAVE_STRUCT_PPB_CORE
|
||||
typedef struct PPB_Core PPB_Core;
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_PPB_MESSAGING
|
||||
typedef struct PPB_Messaging PPB_Messaging;
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_PPB_VAR
|
||||
typedef struct PPB_Var PPB_Var;
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_PPB_URLLOADER
|
||||
typedef struct PPB_URLLoader PPB_URLLoader;
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_PPB_URLREQUESTINFO
|
||||
typedef struct PPB_URLRequestInfo PPB_URLRequestInfo;
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_PPB_URLRESPONSEINFO
|
||||
typedef struct PPB_URLResponseInfo PPB_URLResponseInfo;
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_PPP_INSTANCE
|
||||
typedef struct PPP_Instance PPP_Instance;
|
||||
#endif
|
||||
|
||||
static PP_Module module_id = 0;
|
||||
static PPB_Core* core_interface = NULL;
|
||||
static PPB_Messaging* messaging_interface = NULL;
|
||||
static PPB_Var* var_interface = NULL;
|
||||
static PPB_URLLoader* loader_interface = NULL;
|
||||
static PPB_URLRequestInfo* request_interface = NULL;
|
||||
static PPB_URLResponseInfo* response_interface = NULL;
|
||||
static PPB_FileRef* fileref_interface = NULL;
|
||||
static struct st_table* instance_data = NULL;
|
||||
|
||||
static VALUE instance_table = Qundef;
|
||||
|
||||
static PP_Instance current_instance = 0;
|
||||
|
||||
/******************************************************************************
|
||||
* State of instance
|
||||
******************************************************************************/
|
||||
|
||||
static void inst_mark(void *const ptr);
|
||||
static void inst_free(void *const ptr);
|
||||
static size_t inst_memsize(void *const ptr);
|
||||
static const rb_data_type_t pepper_instance_data_type = {
|
||||
"PepperInstance",
|
||||
{ inst_mark, inst_free, inst_memsize }
|
||||
};
|
||||
|
||||
struct PepperInstance {
|
||||
PP_Instance instance;
|
||||
PP_Resource url_loader;
|
||||
VALUE self;
|
||||
void* async_call_args;
|
||||
union {
|
||||
int32_t as_int;
|
||||
const char* as_str;
|
||||
VALUE as_value;
|
||||
} async_call_result;
|
||||
char buf[1000];
|
||||
|
||||
pthread_t th;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
struct PepperInstance*
|
||||
pruby_get_instance(PP_Instance instance)
|
||||
{
|
||||
VALUE self = rb_hash_aref(instance_table, INT2FIX(instance));
|
||||
if (RTEST(self)) {
|
||||
struct PepperInstance *inst;
|
||||
TypedData_Get_Struct(self, struct PepperInstance, &pepper_instance_data_type, inst);
|
||||
return inst;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define GET_PEPPER_INSTANCE() (pruby_get_instance(current_instance))
|
||||
|
||||
struct PepperInstance*
|
||||
pruby_register_instance(PP_Instance instance)
|
||||
{
|
||||
VALUE obj;
|
||||
struct PepperInstance *data;
|
||||
obj = TypedData_Make_Struct(rb_cData, struct PepperInstance, &pepper_instance_data_type, data);
|
||||
data->self = obj;
|
||||
data->instance = instance;
|
||||
data->url_loader = 0;
|
||||
|
||||
pthread_mutex_init(&data->mutex, NULL);
|
||||
pthread_cond_init(&data->cond, NULL);
|
||||
|
||||
rb_hash_aset(instance_table, INT2FIX(instance), obj);
|
||||
return data;
|
||||
}
|
||||
|
||||
int
|
||||
pruby_unregister_instance(PP_Instance instance)
|
||||
{
|
||||
VALUE inst = rb_hash_delete(instance_table, INT2FIX(instance));
|
||||
return RTEST(inst);
|
||||
}
|
||||
|
||||
static void
|
||||
inst_mark(void *const ptr)
|
||||
{
|
||||
RUBY_MARK_ENTER("PepperInstance"0);
|
||||
if (ptr) {
|
||||
const struct PepperInstance* inst = (struct PepperInstance*)ptr;
|
||||
RUBY_MARK_UNLESS_NULL(inst->async_call_result.as_value);
|
||||
}
|
||||
RUBY_MARK_LEAVE("PepperInstance"0);
|
||||
}
|
||||
|
||||
static void
|
||||
inst_free(void *const ptr)
|
||||
{
|
||||
ruby_xfree(ptr);
|
||||
}
|
||||
|
||||
static size_t
|
||||
inst_memsize(void *const ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
const struct PepperInstance* inst = (struct PepperInstance*)ptr;
|
||||
return sizeof(*inst);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pruby_async_return_int(void* data, int32_t result)
|
||||
{
|
||||
/* PPAPI main thread */
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
instance->async_call_result.as_int = result;
|
||||
if (pthread_cond_signal(&instance->cond)) {
|
||||
perror("pepper-ruby:pthread_cond_signal");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pruby_async_return_str(void* data, const char *result)
|
||||
{
|
||||
/* PPAPI main thread */
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
instance->async_call_result.as_str = result;
|
||||
if (pthread_cond_signal(&instance->cond)) {
|
||||
perror("pepper-ruby:pthread_cond_signal");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pruby_async_return_value(void* data, VALUE value)
|
||||
{
|
||||
/* PPAPI main thread */
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
instance->async_call_result.as_value = value;
|
||||
if (pthread_cond_signal(&instance->cond)) {
|
||||
perror("pepper-ruby:pthread_cond_signal");
|
||||
}
|
||||
}
|
||||
/******************************************************************************
|
||||
* Conversion between Ruby's VALUE, Pepper's Var and C string
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Creates a new string PP_Var from C string. The resulting object will be a
|
||||
* refcounted string object. It will be AddRef()ed for the caller. When the
|
||||
* caller is done with it, it should be Release()d.
|
||||
* @param[in] str C string to be converted to PP_Var
|
||||
* @return PP_Var containing string.
|
||||
*/
|
||||
static struct PP_Var
|
||||
pruby_cstr_to_var(const char* str)
|
||||
{
|
||||
#ifdef PPB_VAR_INTERFACE_1_0
|
||||
if (var_interface != NULL)
|
||||
return var_interface->VarFromUtf8(module_id, str, strlen(str));
|
||||
return PP_MakeUndefined();
|
||||
#else
|
||||
return var_interface->VarFromUtf8(str, strlen(str));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable C string contained in the @a var or NULL if @a var is not
|
||||
* string. This makes a copy of the string in the @a var and adds a NULL
|
||||
* terminator. Note that VarToUtf8() does not guarantee the NULL terminator on
|
||||
* the returned string. See the comments for VarToUtf8() in ppapi/c/ppb_var.h
|
||||
* for more info. The caller is responsible for freeing the returned memory.
|
||||
* @param[in] var PP_Var containing string.
|
||||
* @return a mutable C string representation of @a var.
|
||||
* @note The caller is responsible for freeing the returned string.
|
||||
*/
|
||||
static char*
|
||||
pruby_var_to_cstr(struct PP_Var var)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
if (var_interface != NULL) {
|
||||
const char* var_c_str = var_interface->VarToUtf8(var, &len);
|
||||
if (len > 0) {
|
||||
char* c_str = (char*)malloc(len + 1);
|
||||
memcpy(c_str, var_c_str, len);
|
||||
c_str[len] = '\0';
|
||||
return c_str;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct PP_Var
|
||||
pruby_str_to_var(volatile VALUE str)
|
||||
{
|
||||
if (!RB_TYPE_P(str, T_STRING)) {
|
||||
fprintf(stderr, "[BUG] Unexpected object type: %x\n", TYPE(str));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#ifdef PPB_VAR_INTERFACE_1_0
|
||||
if (var_interface != NULL) {
|
||||
return var_interface->VarFromUtf8(module_id, RSTRING_PTR(str), RSTRING_LEN(str));
|
||||
}
|
||||
#else
|
||||
return var_interface->VarFromUtf8(RSTRING_PTR(str), RSTRING_LEN(str));
|
||||
#endif
|
||||
return PP_MakeUndefined();
|
||||
}
|
||||
|
||||
static struct PP_Var
|
||||
pruby_obj_to_var(volatile VALUE obj)
|
||||
{
|
||||
static const char* const error =
|
||||
"throw 'Failed to convert the result to a JavaScript object';";
|
||||
int state;
|
||||
PUSH_TAG();
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
obj = rb_obj_as_string(obj);
|
||||
}
|
||||
POP_TAG();
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
return pruby_str_to_var(obj);
|
||||
case TAG_RAISE:
|
||||
rb_set_errinfo(Qnil);
|
||||
return pruby_cstr_to_var(error);
|
||||
default:
|
||||
fprintf(stderr, "Fatal error white converting the result to a string\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pruby_var_equal_to_cstr_p(struct PP_Var lhs, const char* rhs)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
if (var_interface == NULL) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
const char* const cstr = var_interface->VarToUtf8(lhs, &len);
|
||||
return strncmp(cstr, rhs, len) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pruby_var_prefixed_p(struct PP_Var var, const char* prefix)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
if (var_interface == NULL) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
const char* const cstr = var_interface->VarToUtf8(var, &len);
|
||||
const size_t prefix_len = strlen(prefix);
|
||||
return len >= prefix_len && memcmp(cstr, prefix, len) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Messaging
|
||||
******************************************************************************/
|
||||
|
||||
/* Posts the given C string as a message.
|
||||
* @param data pointer to a NULL-terminated string */
|
||||
void
|
||||
pruby_post_cstr(void* data)
|
||||
{
|
||||
/* PPAPI main thread */
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
const char* const msg = (const char*)instance->async_call_args;
|
||||
messaging_interface->PostMessage(instance->instance,
|
||||
pruby_cstr_to_var(msg));
|
||||
}
|
||||
|
||||
/* Posts the given Ruby VALUE as a message.
|
||||
* @param data a VALUE casted to void* */
|
||||
void
|
||||
pruby_post_value(void* data)
|
||||
{
|
||||
/* PPAPI main thread */
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
volatile VALUE value = (VALUE)instance->async_call_args;
|
||||
messaging_interface->PostMessage(instance->instance, pruby_obj_to_var(value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Ruby initialization
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
init_loadpath(void)
|
||||
{
|
||||
volatile VALUE path;
|
||||
VALUE load_path = GET_VM()->load_path;
|
||||
|
||||
path = rb_usascii_str_new_cstr("lib/ruby/2.0.0");
|
||||
rb_ary_push(load_path, path);
|
||||
path = rb_usascii_str_new_cstr("lib/ruby/2.0.0/x86_64-nacl");
|
||||
rb_ary_push(load_path, path);
|
||||
|
||||
path = rb_usascii_str_new_cstr(".");
|
||||
rb_ary_push(load_path, path);
|
||||
}
|
||||
|
||||
static void*
|
||||
init_libraries(void* data)
|
||||
{
|
||||
extern void Init_enc();
|
||||
extern void Init_ext();
|
||||
|
||||
int state;
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
current_instance = instance->instance;
|
||||
|
||||
if (pthread_mutex_lock(&instance->mutex)) {
|
||||
perror("pepper-ruby:pthread_mutex_lock");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUSH_TAG();
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
init_loadpath();
|
||||
Init_enc();
|
||||
Init_ext();
|
||||
}
|
||||
POP_TAG();
|
||||
|
||||
pthread_mutex_unlock(&instance->mutex);
|
||||
|
||||
if (state) {
|
||||
volatile VALUE err = rb_errinfo();
|
||||
err = rb_obj_as_string(err);
|
||||
} else {
|
||||
instance->async_call_args = "rubyReady";
|
||||
core_interface->CallOnMainThread(
|
||||
0, PP_MakeCompletionCallback(pruby_post_cstr, instance), 0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
init_libraries_if_necessary(void)
|
||||
{
|
||||
static int initialized = 0;
|
||||
if (!initialized) {
|
||||
struct PepperInstance* const instance = GET_PEPPER_INSTANCE();
|
||||
int err;
|
||||
initialized = 1;
|
||||
err = pthread_create(&instance->th, NULL, &init_libraries, instance);
|
||||
if (err) {
|
||||
fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_detach(instance->th);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pruby_init(void)
|
||||
{
|
||||
RUBY_INIT_STACK;
|
||||
ruby_init();
|
||||
|
||||
instance_table = rb_hash_new();
|
||||
rb_gc_register_mark_object(instance_table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Ruby evaluation
|
||||
******************************************************************************/
|
||||
|
||||
static void*
|
||||
pruby_eval(void* data)
|
||||
{
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
volatile VALUE src = (VALUE)instance->async_call_args;
|
||||
volatile VALUE iseq, result = Qnil;
|
||||
volatile VALUE filename;
|
||||
NODE* tree;
|
||||
volatile int state;
|
||||
rb_thread_t *th;
|
||||
rb_env_t *env;
|
||||
|
||||
RUBY_INIT_STACK;
|
||||
PUSH_TAG();
|
||||
|
||||
if (pthread_mutex_lock(&instance->mutex)) {
|
||||
perror("pepper-ruby:pthread_mutex_lock");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
th = GET_THREAD();
|
||||
SAVE_ROOT_JMPBUF(th, {
|
||||
th->mild_compile_error++;
|
||||
tree = rb_compile_string("(pepper-ruby)", src, 1);
|
||||
th->mild_compile_error--;
|
||||
if (RTEST(rb_errinfo())) {
|
||||
rb_exc_raise(rb_errinfo());
|
||||
}
|
||||
|
||||
{
|
||||
VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
|
||||
rb_binding_t *bind;
|
||||
|
||||
GetBindingPtr(toplevel_binding, bind);
|
||||
GetEnvPtr(bind->env, env);
|
||||
}
|
||||
|
||||
filename = rb_usascii_str_new("(pepper-ruby)", strlen("(pepper-ruby)"));
|
||||
th->parse_in_eval--;
|
||||
th->base_block = &env->block;
|
||||
iseq = rb_iseq_new_main(tree, filename, filename);
|
||||
th->parse_in_eval++;
|
||||
th->base_block = 0;
|
||||
|
||||
result = rb_iseq_eval_main(iseq);
|
||||
});
|
||||
}
|
||||
POP_TAG();
|
||||
|
||||
pthread_mutex_unlock(&instance->mutex);
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
instance->async_call_args =
|
||||
rb_str_concat(rb_usascii_str_new_cstr("return:"),
|
||||
rb_obj_as_string(result));
|
||||
core_interface->CallOnMainThread(
|
||||
0, PP_MakeCompletionCallback(pruby_post_value, instance), 0);
|
||||
return NULL;
|
||||
case TAG_RAISE:
|
||||
result = rb_errinfo();
|
||||
rb_set_errinfo(Qnil);
|
||||
instance->async_call_args =
|
||||
rb_str_concat(rb_usascii_str_new_cstr("error:"),
|
||||
rb_obj_as_string(result));
|
||||
core_interface->CallOnMainThread(
|
||||
0, PP_MakeCompletionCallback(pruby_post_value, instance), 0);
|
||||
return NULL;
|
||||
default:
|
||||
fprintf(stderr, "Fatal error\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Pepper Module callbacks
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Called when the NaCl module is instantiated on the web page. The identifier
|
||||
* of the new instance will be passed in as the first argument (this value is
|
||||
* generated by the browser and is an opaque handle). This is called for each
|
||||
* instantiation of the NaCl module, which is each time the <embed> tag for
|
||||
* this module is encountered.
|
||||
*
|
||||
* If this function reports a failure (by returning @a PP_FALSE), the NaCl
|
||||
* module will be deleted and DidDestroy will be called.
|
||||
* @param[in] instance The identifier of the new instance representing this
|
||||
* NaCl module.
|
||||
* @param[in] argc The number of arguments contained in @a argn and @a argv.
|
||||
* @param[in] argn An array of argument names. These argument names are
|
||||
* supplied in the <embed> tag, for example:
|
||||
* <embed id="nacl_module" dimensions="2">
|
||||
* will produce two arguments, one named "id" and one named "dimensions".
|
||||
* @param[in] argv An array of argument values. These are the values of the
|
||||
* arguments listed in the <embed> tag. In the above example, there will
|
||||
* be two elements in this array, "nacl_module" and "2". The indices of
|
||||
* these values match the indices of the corresponding names in @a argn.
|
||||
* @return @a PP_TRUE on success.
|
||||
*/
|
||||
static PP_Bool
|
||||
Instance_DidCreate(PP_Instance instance,
|
||||
uint32_t argc, const char* argn[], const char* argv[])
|
||||
{
|
||||
struct PepperInstance* data = pruby_register_instance(instance);
|
||||
current_instance = instance;
|
||||
return init_libraries_if_necessary() ? PP_FALSE : PP_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the NaCl module is destroyed. This will always be called,
|
||||
* even if DidCreate returned failure. This routine should deallocate any data
|
||||
* associated with the instance.
|
||||
* @param[in] instance The identifier of the instance representing this NaCl
|
||||
* module.
|
||||
*/
|
||||
static void Instance_DidDestroy(PP_Instance instance) {
|
||||
struct PepperInstance* data = pruby_get_instance(instance);
|
||||
core_interface->ReleaseResource(data->url_loader);
|
||||
pruby_unregister_instance(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the position, the size, or the clip rect of the element in the
|
||||
* browser that corresponds to this NaCl module has changed.
|
||||
* @param[in] instance The identifier of the instance representing this NaCl
|
||||
* module.
|
||||
* @param[in] position The location on the page of this NaCl module. This is
|
||||
* relative to the top left corner of the viewport, which changes as the
|
||||
* page is scrolled.
|
||||
* @param[in] clip The visible region of the NaCl module. This is relative to
|
||||
* the top left of the plugin's coordinate system (not the page). If the
|
||||
* plugin is invisible, @a clip will be (0, 0, 0, 0).
|
||||
*/
|
||||
#ifdef PPP_INSTANCE_INTERFACE_1_0
|
||||
static void
|
||||
Instance_DidChangeView(PP_Instance instance,
|
||||
const struct PP_Rect* position,
|
||||
const struct PP_Rect* clip)
|
||||
{
|
||||
}
|
||||
#else
|
||||
static void
|
||||
Instance_DidChangeView(PP_Instance instance, PP_Resource view_resource)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Notification that the given NaCl module has gained or lost focus.
|
||||
* Having focus means that keyboard events will be sent to the NaCl module
|
||||
* represented by @a instance. A NaCl module's default condition is that it
|
||||
* will not have focus.
|
||||
*
|
||||
* Note: clicks on NaCl modules will give focus only if you handle the
|
||||
* click event. You signal if you handled it by returning @a true from
|
||||
* HandleInputEvent. Otherwise the browser will bubble the event and give
|
||||
* focus to the element on the page that actually did end up consuming it.
|
||||
* If you're not getting focus, check to make sure you're returning true from
|
||||
* the mouse click in HandleInputEvent.
|
||||
* @param[in] instance The identifier of the instance representing this NaCl
|
||||
* module.
|
||||
* @param[in] has_focus Indicates whether this NaCl module gained or lost
|
||||
* event focus.
|
||||
*/
|
||||
static void
|
||||
Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler that gets called after a full-frame module is instantiated based on
|
||||
* registered MIME types. This function is not called on NaCl modules. This
|
||||
* function is essentially a place-holder for the required function pointer in
|
||||
* the PPP_Instance structure.
|
||||
* @param[in] instance The identifier of the instance representing this NaCl
|
||||
* module.
|
||||
* @param[in] url_loader A PP_Resource an open PPB_URLLoader instance.
|
||||
* @return PP_FALSE.
|
||||
*/
|
||||
static PP_Bool
|
||||
Instance_HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader)
|
||||
{
|
||||
/* NaCl modules do not need to handle the document load function. */
|
||||
return PP_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for messages coming in from the browser via postMessage. The
|
||||
* @a var_message can contain anything: a JSON string; a string that encodes
|
||||
* method names and arguments; etc. For example, you could use JSON.stringify
|
||||
* in the browser to create a message that contains a method name and some
|
||||
* parameters, something like this:
|
||||
* var json_message = JSON.stringify({ "myMethod" : "3.14159" });
|
||||
* nacl_module.postMessage(json_message);
|
||||
* On receipt of this message in @a var_message, you could parse the JSON to
|
||||
* retrieve the method name, match it to a function call, and then call it with
|
||||
* the parameter.
|
||||
* @param[in] instance The instance ID.
|
||||
* @param[in] message The contents, copied by value, of the message sent from
|
||||
* browser via postMessage.
|
||||
*/
|
||||
void
|
||||
Messaging_HandleMessage(PP_Instance instance, struct PP_Var var_message)
|
||||
{
|
||||
char* const message = pruby_var_to_cstr(var_message);
|
||||
size_t message_len = strlen(message);
|
||||
current_instance = instance;
|
||||
|
||||
if (strstr(message, "eval:") != NULL) {
|
||||
volatile VALUE src;
|
||||
struct PepperInstance* const instance_data = GET_PEPPER_INSTANCE();
|
||||
int err;
|
||||
#define EVAL_PREFIX_LEN 5
|
||||
src = rb_str_new(message + EVAL_PREFIX_LEN, message_len - EVAL_PREFIX_LEN);
|
||||
instance_data->async_call_args = (void*)src;
|
||||
err = pthread_create(&instance_data->th, NULL, &pruby_eval, instance_data);
|
||||
if (err) {
|
||||
fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_detach(instance_data->th);
|
||||
}
|
||||
free(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry points for the module.
|
||||
* Initialize instance interface and scriptable object class.
|
||||
* @param[in] a_module_id Module ID
|
||||
* @param[in] get_browser_interface Pointer to PPB_GetInterface
|
||||
* @return PP_OK on success, any other value on failure.
|
||||
*/
|
||||
PP_EXPORT int32_t
|
||||
PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface get_browser_interface)
|
||||
{
|
||||
module_id = a_module_id;
|
||||
core_interface = (PPB_Core*)(get_browser_interface(PPB_CORE_INTERFACE));
|
||||
if (core_interface == NULL) return PP_ERROR_NOINTERFACE;
|
||||
|
||||
var_interface = (PPB_Var*)(get_browser_interface(PPB_VAR_INTERFACE));
|
||||
if (var_interface == NULL) return PP_ERROR_NOINTERFACE;
|
||||
|
||||
messaging_interface = (PPB_Messaging*)(get_browser_interface(PPB_MESSAGING_INTERFACE));
|
||||
if (messaging_interface == NULL) return PP_ERROR_NOINTERFACE;
|
||||
|
||||
loader_interface = (PPB_URLLoader*)(get_browser_interface(PPB_URLLOADER_INTERFACE));
|
||||
if (loader_interface == NULL) return PP_ERROR_NOINTERFACE;
|
||||
|
||||
request_interface = (PPB_URLRequestInfo*)(get_browser_interface(PPB_URLREQUESTINFO_INTERFACE));
|
||||
if (request_interface == NULL) return PP_ERROR_NOINTERFACE;
|
||||
|
||||
response_interface = (PPB_URLResponseInfo*)(get_browser_interface(PPB_URLRESPONSEINFO_INTERFACE));
|
||||
if (response_interface == NULL) return PP_ERROR_NOINTERFACE;
|
||||
|
||||
fileref_interface = (PPB_FileRef*)(get_browser_interface(PPB_FILEREF_INTERFACE));
|
||||
if (fileref_interface == NULL) return PP_ERROR_NOINTERFACE;
|
||||
|
||||
return pruby_init() ? PP_ERROR_FAILED : PP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an interface pointer for the interface of the given name, or NULL
|
||||
* if the interface is not supported.
|
||||
* @param[in] interface_name name of the interface
|
||||
* @return pointer to the interface
|
||||
*/
|
||||
PP_EXPORT const void*
|
||||
PPP_GetInterface(const char* interface_name)
|
||||
{
|
||||
if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
|
||||
static PPP_Instance instance_interface = {
|
||||
&Instance_DidCreate,
|
||||
&Instance_DidDestroy,
|
||||
&Instance_DidChangeView,
|
||||
&Instance_DidChangeFocus,
|
||||
&Instance_HandleDocumentLoad
|
||||
};
|
||||
return &instance_interface;
|
||||
} else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
|
||||
static PPP_Messaging messaging_interface = {
|
||||
&Messaging_HandleMessage
|
||||
};
|
||||
return &messaging_interface;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the plugin module is unloaded.
|
||||
*/
|
||||
PP_EXPORT void
|
||||
PPP_ShutdownModule()
|
||||
{
|
||||
ruby_cleanup(0);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Overwrites rb_file_load_ok
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
load_ok_internal(void* data, int32_t unused)
|
||||
{
|
||||
/* PPAPI main thread */
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
const char *const path = (const char*)instance->async_call_args;
|
||||
PP_Resource req;
|
||||
int result;
|
||||
|
||||
instance->url_loader = loader_interface->Create(instance->instance);
|
||||
req = request_interface->Create(instance->instance);
|
||||
request_interface->SetProperty(
|
||||
req, PP_URLREQUESTPROPERTY_METHOD, pruby_cstr_to_var("HEAD"));
|
||||
request_interface->SetProperty(
|
||||
req, PP_URLREQUESTPROPERTY_URL, pruby_cstr_to_var(path));
|
||||
|
||||
result = loader_interface->Open(
|
||||
instance->url_loader, req,
|
||||
PP_MakeCompletionCallback(pruby_async_return_int, instance));
|
||||
if (result != PP_OK_COMPLETIONPENDING) {
|
||||
pruby_async_return_int(instance, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pruby_file_fetch_check_response(void* data, int32_t unused)
|
||||
{
|
||||
/* PPAPI main thread */
|
||||
PP_Resource res;
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
|
||||
res = loader_interface->GetResponseInfo(instance->url_loader);
|
||||
if (res) {
|
||||
struct PP_Var status =
|
||||
response_interface->GetProperty(res, PP_URLRESPONSEPROPERTY_STATUSCODE);
|
||||
if (status.type == PP_VARTYPE_INT32) {
|
||||
pruby_async_return_int(instance, status.value.as_int / 100 == 2 ? PP_OK : PP_ERROR_FAILED);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
messaging_interface->PostMessage(
|
||||
instance->instance, pruby_cstr_to_var("Unexpected type: ResponseInfoInterface::GetProperty"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
messaging_interface->PostMessage(
|
||||
instance->instance, pruby_cstr_to_var("Failed to open URL: URLLoaderInterface::GetResponseInfo"));
|
||||
}
|
||||
pruby_async_return_int(instance, PP_ERROR_FAILED);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rb_file_load_ok(const char *path)
|
||||
{
|
||||
struct PepperInstance* const instance = GET_PEPPER_INSTANCE();
|
||||
if (path[0] == '.' && path[1] == '/') path += 2;
|
||||
|
||||
instance->async_call_args = (void*)path;
|
||||
core_interface->CallOnMainThread(
|
||||
0, PP_MakeCompletionCallback(load_ok_internal, instance), 0);
|
||||
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
|
||||
perror("pepper-ruby:pthread_cond_wait");
|
||||
return 0;
|
||||
}
|
||||
if (instance->async_call_result.as_int != PP_OK) {
|
||||
fprintf(stderr, "Failed to open URL: %d: %s\n",
|
||||
instance->async_call_result.as_int, path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
core_interface->CallOnMainThread(
|
||||
0, PP_MakeCompletionCallback(pruby_file_fetch_check_response, instance), 0);
|
||||
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
|
||||
perror("pepper-ruby:pthread_cond_wait");
|
||||
return 0;
|
||||
}
|
||||
return instance->async_call_result.as_int == PP_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Overwrites rb_load_file
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
load_file_internal(void* data, int32_t unused)
|
||||
{
|
||||
/* PPAPI main thread */
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
const char *const path = (const char*)instance->async_call_args;
|
||||
PP_Resource req;
|
||||
int result;
|
||||
|
||||
instance->url_loader = loader_interface->Create(instance->instance);
|
||||
req = request_interface->Create(instance->instance);
|
||||
request_interface->SetProperty(
|
||||
req, PP_URLREQUESTPROPERTY_METHOD, pruby_cstr_to_var("GET"));
|
||||
request_interface->SetProperty(
|
||||
req, PP_URLREQUESTPROPERTY_URL, pruby_cstr_to_var(path));
|
||||
|
||||
result = loader_interface->Open(
|
||||
instance->url_loader, req,
|
||||
PP_MakeCompletionCallback(pruby_async_return_int, instance));
|
||||
if (result != PP_OK_COMPLETIONPENDING) {
|
||||
pruby_async_return_int(instance, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
load_file_read_contents_callback(void *data, int result)
|
||||
{
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
if (result > 0) {
|
||||
rb_str_buf_cat(instance->async_call_result.as_value,
|
||||
instance->buf, result);
|
||||
loader_interface->ReadResponseBody(
|
||||
instance->url_loader, instance->buf, 1000, PP_MakeCompletionCallback(load_file_read_contents_callback, instance));
|
||||
}
|
||||
else if (result == 0) {
|
||||
pruby_async_return_value(data, instance->async_call_result.as_value);
|
||||
}
|
||||
else {
|
||||
pruby_async_return_value(data, INT2FIX(result));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
load_file_read_contents(void *data, int result)
|
||||
{
|
||||
struct PepperInstance* const instance = (struct PepperInstance*)data;
|
||||
instance->async_call_result.as_value = rb_str_new(0, 0);
|
||||
loader_interface->ReadResponseBody(
|
||||
instance->url_loader, instance->buf, 1000, PP_MakeCompletionCallback(load_file_read_contents_callback, instance));
|
||||
}
|
||||
|
||||
void*
|
||||
rb_load_file(const char *path)
|
||||
{
|
||||
const char *real_path;
|
||||
struct PepperInstance* instance;
|
||||
if (path[0] != '.' || path[1] != '/') path += 2;
|
||||
|
||||
instance = GET_PEPPER_INSTANCE();
|
||||
|
||||
instance->async_call_args = (void*)path;
|
||||
core_interface->CallOnMainThread(
|
||||
0, PP_MakeCompletionCallback(load_file_internal, instance), 0);
|
||||
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
|
||||
perror("pepper-ruby:pthread_cond_wait");
|
||||
return 0;
|
||||
}
|
||||
if (instance->async_call_result.as_int != PP_OK) {
|
||||
fprintf(stderr, "Failed to open URL: %d: %s\n",
|
||||
instance->async_call_result.as_int, path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
core_interface->CallOnMainThread(
|
||||
0, PP_MakeCompletionCallback(pruby_file_fetch_check_response, instance), 0);
|
||||
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
|
||||
perror("pepper-ruby:pthread_cond_wait");
|
||||
return 0;
|
||||
}
|
||||
if (instance->async_call_result.as_int != PP_OK) return 0;
|
||||
|
||||
core_interface->CallOnMainThread(
|
||||
0, PP_MakeCompletionCallback(load_file_read_contents, instance), 0);
|
||||
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
|
||||
perror("pepper-ruby:pthread_cond_wait");
|
||||
return 0;
|
||||
}
|
||||
if (FIXNUM_P(instance->async_call_result.as_value)) {
|
||||
return 0;
|
||||
}
|
||||
else if (RB_TYPE_P(instance->async_call_result.as_value, T_STRING)) {
|
||||
VALUE str = instance->async_call_result.as_value;
|
||||
return rb_compile_cstr(path, RSTRING_PTR(str), RSTRING_LEN(str), 0);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
8
nacl/resource.h
Normal file
8
nacl/resource.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc. All Rights Reserved.
|
||||
* Author: yugui@google.com (Yugui Sonoda)
|
||||
* */
|
||||
#ifndef RUBY_NACL_RESOURCE_H
|
||||
#define RUBY_NACL_RESOURCE_H
|
||||
int getrusage(int who, struct rusage *usage);
|
||||
#endif
|
7
nacl/select.h
Normal file
7
nacl/select.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
// Author: yugui@google.com (Yugui Sonoda)
|
||||
#ifndef RUBY_NACL_SELECT_H
|
||||
#define RUBY_NACL_SELECT_H
|
||||
int select(int num_fds, fd_set *in_fds, fd_set *out_fds,
|
||||
fd_set *ex_fds, struct timeval *timeout);
|
||||
#endif
|
6
nacl/signal.h
Normal file
6
nacl/signal.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
// Author: yugui@google.com (Yugui Sonoda)
|
||||
#ifndef RUBY_NACL_SIGNAL_H
|
||||
#define RUBY_NACL_SIGNAL_H
|
||||
int kill(pid_t pid, int signal);
|
||||
#endif
|
10
nacl/stat.h
Normal file
10
nacl/stat.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc. All Rights Reserved.
|
||||
* Author: yugui@google.com (Yugui Sonoda)
|
||||
* */
|
||||
#ifndef RUBY_NACL_STAT_H
|
||||
#define RUBY_NACL_STAT_H
|
||||
mode_t umask(mode_t mask);
|
||||
struct stat;
|
||||
int lstat(const char* path, struct stat* result);
|
||||
#endif
|
9
nacl/unistd.h
Normal file
9
nacl/unistd.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
// Author: yugui@google.com (Yugui Sonoda)
|
||||
#ifndef RUBY_NACL_UNISTD_H
|
||||
#define RUBY_NACL_UNISTD_H
|
||||
int seteuid(pid_t pid);
|
||||
int setegid(pid_t pid);
|
||||
int truncate(const char* path, off_t new_size);
|
||||
int ftruncate(int fd, off_t new_size);
|
||||
#endif
|
11
nacl/utime.h
Normal file
11
nacl/utime.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc. All Rights Reserved.
|
||||
* Author: yugui@google.com (Yugui Sonoda)
|
||||
*/
|
||||
|
||||
#ifndef RUBY_NACL_UTIME_H
|
||||
#define RUBY_NACL_UTIME_H
|
||||
#include <utime.h>
|
||||
int utime(const char *filename, const struct utimbuf *times);
|
||||
int utimes(const char *filename, const struct timeval times[2]);
|
||||
#endif
|
37
process.c
37
process.c
|
@ -62,6 +62,11 @@
|
|||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#if defined(__native_client__) && defined(NACL_NEWLIB)
|
||||
# include "nacl/stat.h"
|
||||
# include "nacl/unistd.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_SYS_TIMES_H
|
||||
#include <sys/times.h>
|
||||
|
@ -1042,7 +1047,7 @@ security(const char *str)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_FORK
|
||||
#if defined(HAVE_FORK) && !defined(__native_client__)
|
||||
#define try_with_sh(prog, argv) ((saved_errno == ENOEXEC) ? exec_with_sh((prog), (argv)) : (void)0)
|
||||
static void
|
||||
exec_with_sh(const char *prog, char **argv)
|
||||
|
@ -1061,13 +1066,20 @@ exec_with_sh(const char *prog, char **argv)
|
|||
#define ALLOC_ARGV_WITH_STR(n, v, s, l) \
|
||||
(char **)(((s) = ALLOCV_N(char, (v), ARGV_SIZE(n) + (l)) + ARGV_SIZE(n)) - ARGV_SIZE(n))
|
||||
|
||||
#ifdef __native_client__
|
||||
static int
|
||||
proc_exec_v(char **argv, const char *prog)
|
||||
{
|
||||
rb_notimplement();
|
||||
}
|
||||
#else
|
||||
static int
|
||||
proc_exec_v(char **argv, const char *prog)
|
||||
{
|
||||
char fbuf[MAXPATHLEN];
|
||||
#if defined(__EMX__) || defined(OS2)
|
||||
# if defined(__EMX__) || defined(OS2)
|
||||
char **new_argv = NULL;
|
||||
#endif
|
||||
# endif
|
||||
|
||||
if (!prog)
|
||||
prog = argv[0];
|
||||
|
@ -1077,9 +1089,9 @@ proc_exec_v(char **argv, const char *prog)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__EMX__) || defined(OS2)
|
||||
# if defined(__EMX__) || defined(OS2)
|
||||
{
|
||||
#define COMMAND "cmd.exe"
|
||||
# define COMMAND "cmd.exe"
|
||||
char *extension;
|
||||
|
||||
if ((extension = strrchr(prog, '.')) != NULL && STRCASECMP(extension, ".bat") == 0) {
|
||||
|
@ -1104,18 +1116,19 @@ proc_exec_v(char **argv, const char *prog)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif /* __EMX__ */
|
||||
# endif /* __EMX__ */
|
||||
before_exec();
|
||||
execv(prog, argv);
|
||||
preserving_errno(try_with_sh(prog, argv); after_exec());
|
||||
#if defined(__EMX__) || defined(OS2)
|
||||
# if defined(__EMX__) || defined(OS2)
|
||||
if (new_argv) {
|
||||
xfree(new_argv[0]);
|
||||
xfree(new_argv);
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
|
||||
|
@ -1137,6 +1150,13 @@ rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __native_client__
|
||||
int
|
||||
rb_proc_exec(const char *str)
|
||||
{
|
||||
rb_notimplement();
|
||||
}
|
||||
#else
|
||||
int
|
||||
rb_proc_exec(const char *str)
|
||||
{
|
||||
|
@ -1206,6 +1226,7 @@ rb_proc_exec(const char *str)
|
|||
return ret;
|
||||
#endif /* _WIN32 */
|
||||
}
|
||||
#endif
|
||||
|
||||
enum {
|
||||
EXEC_OPTION_PGROUP,
|
||||
|
|
7
signal.c
7
signal.c
|
@ -18,6 +18,10 @@
|
|||
#include <errno.h>
|
||||
#include "atomic.h"
|
||||
|
||||
#if defined(__native_client__) && defined(NACL_NEWLIB)
|
||||
# include "nacl/signal.h"
|
||||
#endif
|
||||
|
||||
#ifdef NEED_RUBY_ATOMIC_EXCHANGE
|
||||
rb_atomic_t
|
||||
ruby_atomic_exchange(rb_atomic_t *ptr, rb_atomic_t val)
|
||||
|
@ -417,8 +421,6 @@ typedef RETSIGTYPE ruby_sigaction_t(int);
|
|||
#define SIGINFO_ARG
|
||||
#endif
|
||||
|
||||
#ifdef POSIX_SIGNAL
|
||||
|
||||
#ifdef USE_SIGALTSTACK
|
||||
/* alternate stack for SIGSEGV */
|
||||
void
|
||||
|
@ -437,6 +439,7 @@ rb_register_sigaltstack(rb_thread_t *th)
|
|||
}
|
||||
#endif /* USE_SIGALTSTACK */
|
||||
|
||||
#ifdef POSIX_SIGNAL
|
||||
static sighandler_t
|
||||
ruby_signal(int signum, sighandler_t handler)
|
||||
{
|
||||
|
|
10
thread.c
10
thread.c
|
@ -2420,6 +2420,11 @@ rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
|
|||
memcpy(dst->fdset, src->fdset, size);
|
||||
}
|
||||
|
||||
#ifdef __native_client__
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds, struct timeval *timeout);
|
||||
#endif
|
||||
|
||||
int
|
||||
rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout)
|
||||
{
|
||||
|
@ -3298,7 +3303,9 @@ mutex_free(void *ptr)
|
|||
if (err) rb_bug("%s", err);
|
||||
}
|
||||
native_mutex_destroy(&mutex->lock);
|
||||
#ifdef HAVE_PTHREAD_COND_INITIALIZE
|
||||
native_cond_destroy(&mutex->cond);
|
||||
#endif
|
||||
}
|
||||
ruby_xfree(ptr);
|
||||
}
|
||||
|
@ -3333,7 +3340,9 @@ mutex_alloc(VALUE klass)
|
|||
|
||||
obj = TypedData_Make_Struct(klass, rb_mutex_t, &mutex_data_type, mutex);
|
||||
native_mutex_initialize(&mutex->lock);
|
||||
#ifdef HAVE_PTHREAD_COND_INITIALIZE
|
||||
native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC);
|
||||
#endif
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -4781,4 +4790,3 @@ rb_reset_coverages(void)
|
|||
GET_VM()->coverages = Qfalse;
|
||||
rb_remove_event_hook(update_coverage);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#if HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
#if defined(__native_client__) && defined(NACL_NEWLIB)
|
||||
# include "nacl/select.h"
|
||||
#endif
|
||||
|
||||
static void native_mutex_lock(pthread_mutex_t *lock);
|
||||
static void native_mutex_unlock(pthread_mutex_t *lock);
|
||||
|
@ -137,9 +140,11 @@ static void
|
|||
gvl_init(rb_vm_t *vm)
|
||||
{
|
||||
native_mutex_initialize(&vm->gvl.lock);
|
||||
#ifdef HAVE_PTHREAD_CONDATTR_INIT
|
||||
native_cond_initialize(&vm->gvl.cond, RB_CONDATTR_CLOCK_MONOTONIC);
|
||||
native_cond_initialize(&vm->gvl.switch_cond, RB_CONDATTR_CLOCK_MONOTONIC);
|
||||
native_cond_initialize(&vm->gvl.switch_wait_cond, RB_CONDATTR_CLOCK_MONOTONIC);
|
||||
#endif
|
||||
vm->gvl.acquired = 0;
|
||||
vm->gvl.waiting = 0;
|
||||
vm->gvl.need_yield = 0;
|
||||
|
@ -148,9 +153,11 @@ gvl_init(rb_vm_t *vm)
|
|||
static void
|
||||
gvl_destroy(rb_vm_t *vm)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_CONDATTR_INIT
|
||||
native_cond_destroy(&vm->gvl.switch_wait_cond);
|
||||
native_cond_destroy(&vm->gvl.switch_cond);
|
||||
native_cond_destroy(&vm->gvl.cond);
|
||||
#endif
|
||||
native_mutex_destroy(&vm->gvl.lock);
|
||||
}
|
||||
|
||||
|
@ -232,6 +239,9 @@ native_mutex_destroy(pthread_mutex_t *lock)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PTHREAD_CONDATTR_INIT
|
||||
int pthread_condattr_init(pthread_condattr_t *attr);
|
||||
|
||||
static void
|
||||
native_cond_initialize(rb_thread_cond_t *cond, int flags)
|
||||
{
|
||||
|
@ -266,6 +276,7 @@ native_cond_destroy(rb_thread_cond_t *cond)
|
|||
rb_bug_errno("pthread_cond_destroy", r);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In OS X 10.7 (Lion), pthread_cond_signal and pthread_cond_broadcast return
|
||||
|
@ -439,20 +450,26 @@ Init_native_thread(void)
|
|||
#ifdef USE_SIGNAL_THREAD_LIST
|
||||
native_mutex_initialize(&signal_thread_list_lock);
|
||||
#endif
|
||||
#ifndef __native_client__
|
||||
posix_signal(SIGVTALRM, null_func);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
native_thread_init(rb_thread_t *th)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_CONDATTR_INIT
|
||||
native_cond_initialize(&th->native_thread_data.sleep_cond, RB_CONDATTR_CLOCK_MONOTONIC);
|
||||
#endif
|
||||
ruby_thread_set_native(th);
|
||||
}
|
||||
|
||||
static void
|
||||
native_thread_destroy(rb_thread_t *th)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_CONDATTR_INIT
|
||||
native_cond_destroy(&th->native_thread_data.sleep_cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define USE_THREAD_CACHE 0
|
||||
|
@ -1197,6 +1214,7 @@ thread_timer(void *p)
|
|||
static void
|
||||
rb_thread_create_timer_thread(void)
|
||||
{
|
||||
#ifndef __native_client__
|
||||
if (!timer_thread_id) {
|
||||
pthread_attr_t attr;
|
||||
int err;
|
||||
|
@ -1256,6 +1274,7 @@ rb_thread_create_timer_thread(void)
|
|||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
10
util.c
10
util.c
|
@ -462,6 +462,15 @@ ruby_strdup(const char *str)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
#ifdef __native_client__
|
||||
char *
|
||||
ruby_getcwd(void)
|
||||
{
|
||||
char *buf = xmalloc(2);
|
||||
strcpy(buf, ".");
|
||||
return buf;
|
||||
}
|
||||
#else
|
||||
char *
|
||||
ruby_getcwd(void)
|
||||
{
|
||||
|
@ -490,6 +499,7 @@ ruby_getcwd(void)
|
|||
#endif
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************
|
||||
*
|
||||
|
|
|
@ -92,6 +92,10 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __native_client__
|
||||
#undef OPT_DIRECT_THREADED_CODE
|
||||
#endif
|
||||
|
||||
/* call threaded code */
|
||||
#if OPT_CALL_THREADED_CODE
|
||||
#if OPT_DIRECT_THREADED_CODE
|
||||
|
|
|
@ -281,6 +281,7 @@ XRUBY = $(MINIRUBY)
|
|||
!else
|
||||
XRUBY = $(RUNRUBY)
|
||||
!endif
|
||||
BTESTRUBY = $(MINIRUBY)
|
||||
!ifndef RUBY
|
||||
RUBY = ruby
|
||||
!endif
|
||||
|
|
Loading…
Reference in a new issue