Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Cleanup of init, wrappers now compiled in. Coro-based [source $url]. Detailed description in README. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | ferrieux-nacl |
Files: | files | file ages | folders |
SHA1: |
4d49dfa58c7572e1c863549e21f963b4 |
User & Date: | ferrieux 2011-04-10 11:25:07 |
Context
2011-04-10
| ||
23:11 | First step of a Tk canvas emulation in NaTcl based on the HTML5 canvas. Optimized for move-only upda... check-in: 6f398fb8ef user: ferrieux tags: ferrieux-nacl | |
11:25 | Cleanup of init, wrappers now compiled in. Coro-based [source $url]. Detailed description in README. check-in: 4d49dfa58c user: ferrieux tags: ferrieux-nacl | |
2011-04-08
| ||
22:47 | First example of a non-trivial event-driven Tcl program interacting with JS. Features after, [bger... check-in: 21b74633e5 user: ferrieux tags: ferrieux-nacl | |
Changes
Changes to nacl/Makefile.patch.
|
| | | | 1 2 3 4 5 6 7 8 9 | --- Makefile 2011-04-10 13:21:12.773175132 +0200 +++ tweaked.Makefile 2011-04-10 12:34:27.256426620 +0200 @@ -102,12 +102,20 @@ #CFLAGS = $(CFLAGS_DEBUG) #CFLAGS = $(CFLAGS_OPTIMIZE) #CFLAGS = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE) -CFLAGS = $(CFLAGS_OPTIMIZE) -Wno-long-long -pthread -DNACL -pipe -fvisibility=hidden +CFLAGS = $(CFLAGS_OPTIMIZE) -pipe -fvisibility=hidden + |
︙ | ︙ | |||
77 78 79 80 81 82 83 | @@ -634,14 +646,34 @@ # Must be empty so it doesn't conflict with rule for ${TCL_EXE} above ${NATIVE_TCLSH}: -Makefile: $(UNIX_DIR)/Makefile.in $(DLTEST_DIR)/Makefile.in - $(SHELL) config.status | | | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | @@ -634,14 +646,34 @@ # Must be empty so it doesn't conflict with rule for ${TCL_EXE} above ${NATIVE_TCLSH}: -Makefile: $(UNIX_DIR)/Makefile.in $(DLTEST_DIR)/Makefile.in - $(SHELL) config.status +init.tcl.c: ../library/init.tcl init.natcl + cat $^ | tools/tocstr > $@ + +tclUnixPort.h: ../unix/tclUnixPort.h tclUnixPort.h.patch + cat ../unix/tclUnixPort.h > tclUnixPort.h + patch -p0 < tclUnixPort.h.patch + +naclMain.o: naclMain.c init.tcl.c + $(CC) -c $(CC_SWITCHES) naclMain.c |
︙ | ︙ |
Changes to nacl/README.
︙ | ︙ | |||
33 34 35 36 37 38 39 | - launch the NaCl-provided python-based webserver, and make it see your nacl dir somewhere in its document tree. e.g. cd $NACL/examples; ln -s /..../tcl/nacl nacl; python httpd.py 5103 - (once) open about:flags in Chrome and enable Native Client | | | > > | > | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | - launch the NaCl-provided python-based webserver, and make it see your nacl dir somewhere in its document tree. e.g. cd $NACL/examples; ln -s /..../tcl/nacl nacl; python httpd.py 5103 - (once) open about:flags in Chrome and enable Native Client - start '(cd tools;./chromedebug)', and point Chrome to the index.html in nacl. e.g. chromedebug http://localhost:5103/nacl. - alternatively, use './chrd' to load the 'balls' demo. - (every time) make sure no non-chromedebug chrome process is running, otherwise it will be used instead, and NaCl will fail to load. Also, when you update or tweak anything, it is a good idea to flush your browser's cache ! - note: 'chromedebug' just sets an env var for debug output (on stderr), and stars chrome with '--no-sandbox', which is currently needed for NaCl to be really enabled on Linux. Overview of the porting method ------------------------------ |
︙ | ︙ | |||
62 63 64 65 66 67 68 69 | error is raised. But one cannot hope much more, it's a sandbox for a reason. This approach allows to compile Tcl for Nacl without changing a single line of the original source distribution; all new things are in the nacl subdir. Also, much is reused from ../unix. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | error is raised. But one cannot hope much more, it's a sandbox for a reason. This approach allows to compile Tcl for Nacl without changing a single line of the original source distribution; all new things are in the nacl subdir. Also, much is reused from ../unix. Nacl context specifics ---------------------- One thing to keep in mind is that NaCl lets us run in our sandbox, in a dedicated process, but at the time of writing, it is in a very synchronous "lockstep" interaction with the main renderer process executing JS code. A more async API allowing us to be in a free-floating thread and exchanging messages with JS is in the works, but not baked yet. Given this, NaTcl simply obeys the rules of the synchronous, event-driven world of JS: do everything in quickly returning event callbacks, never stick for too long. Note that most Tcl/Tk users should feel at home, since it is exactly the recipe for a responsive Tk GUI. For maximal genericity, the way NaTcl "retroacts" on the JS context is by returning a JS string to eval(). Then you can do whatever you want, including of course arranging for future JS events to call back into NaTcl. See [domset] and [after] (in init.natcl, which is compiled into the binray .nexe) as two very simple examples. In an universe without syscalls, loading other scripts is problematic. To circumvent this (and bootstrap the loading of the main script), [source $url] is reimplemented over a JS XmlHttpRequest. And to preserve the blocking semantics of traditional [source] while XHR is purely async, this implementation is coro-based and calls [yield] after starting the request. When the download completes, JS calls back into Tcl to resume the coro, and continue the sequential execution of the Tcl script where it left. This allows for arbitrary series and nesting of [source]. For this reason, the main script is bootstrapped by evaluating: coroutine main_coro source $url This means that all the init code in the script will run in the coro context (for [source]'s benefit, but that could be extended to other things). But once the execution has fallen back out of the main script, hopefully after setting up many (JS) event handlers, it is up to the app to establish other coro contexts if needed. The bottom line is this: - a simple, ol'good-Tk-style event-driven script will not have to bother about coros - a more advanced, coro-savvy script can use coros to do lengthy things (be they computations of network downloads) while leaving the GUI responsive - in all cases, [source] works as usual to fetch scripts over HTTP (in the same domain as the page serving the NaTcl plugin). Relative URLs work: [source foo.natcl]. - in all cases, falling back out of the main scripts is equivalent to going back to the Tk eventloop in wish (except it is the JS eventloop). Future work ----------- Coming soon: [domget], [canvas], and a decent bouncing-balls demo ;-) |
Added nacl/a.natcl.
> > > | 1 2 3 | printf "I'm a.natcl" source c.natcl |
Added nacl/b.natcl.
> > | 1 2 | printf "I'm b.natcl" |
Changes to nacl/balls.html.
1 2 3 4 5 6 7 8 | <!DOCTYPE html> <html> <!-- Copyright (c) 2010 The Native Client Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <head> | > | | > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > < | | | | | | | | > | | | | > | | | < | | | | | | | > > > | > > > > > > > > > > > > > > > > | | | > | | | | | | | | | | | < < < < < < < < < < | < | > | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | <!DOCTYPE html> <html> <!-- Copyright (c) 2010 The Native Client Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <head> <title>NaTcl : Tcl in Nacl</title> <script type="text/javascript"> // NaTcl -- JS glue tclModule = null; // our singleton Tcl interp // debugging stuff function printf(s) { // I like debugging to stderr instead of console.log, // because when things go wrong, the JS console is not // alays reachable. tclModule.eval('printf {'+s+'}'); } function ljoin() { // yeah. 'arguments' is 'similar to an array but not quite' // that's why I think JS has no soul. return Array.prototype.slice.call(arguments).join("\n"); } // --- tclDo is the main JS-Tcl trampoline. // // Its job is to pass a Tcl string to [eval] (through naclwrap, see // init.nacl), and then take back the result as JS and eval() it. // It also detects errors in the latter eval() and pipes them back // to [bgerror]. tclReportError = ""; function tclDo(s) { //printf("do:"+s); try { t = tclModule.eval("naclwrap {"+s+"}"); //printf("ret:"+t); eval(t); } catch(err) { //printf("JS-err:"+err); tclReportError="bgerror {"+err+" -- while doing: "+t+"}"; setTimeout('tclDo(tclReportError)',0); } } // --- tclsource starts an XHR, and calls the given 'tcb' (Tcl // --- Callback) on completion. A catchable Tcl-level error is raised // --- in case of not-200. Used by [source]. function tclsource(url,tcb) { //printf('tclsource'); xs = new XMLHttpRequest(); xs.open("GET",url,true); xs.send(null); xs.onreadystatechange = function() { //printf("XHR-source:"+xs.readyState); if (xs.readyState==4) { if (xs.status==200) { tclDo(tcb+" {"+xs.responseText+"}"); } else { tclDo(tcb+" {error \"Can't source -- "+xs.statusText+"\"}"); } } }; } // ---------- GUI and standard NaCl-loading machinery -------- var statusField = null; modstatus = 'NO-STATUS'; function updateStatus(opt_message) { if (statusField) { statusField.innerHTML = modstatus; } } function moduleDidLoad() { tclModule = document.getElementById('tcl'); updateStatus('NaTcl Loaded ; Fetching and running !'); tclDo('coroutine main_coro source balls.natcl'); } // 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() { statusField = document.getElementById('modstatus'); if (tclModule == null) { updateStatus('Loading Nacl...'); } 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(); } } function doeval() { try { alert(tclModule.eval(this.the_form.input_id.value)); } catch(e) { alert(e.message); } } </script> </head> <body onload="pageDidLoad()"> <h1>NaTcl -- Native Client Tcl Module</h1> <p> <form name="the_form" action="" method="get"> <textarea id="input_id" name="inputbox" rows="15" cols="80">list a b c </textarea><p> <input type="button" value="Call eval()" onclick="doeval()"> </form> <!-- 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 runtime ('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 |
︙ | ︙ | |||
111 112 113 114 115 116 117 | onload="moduleDidLoad();" /> </p> <p>If the module is working correctly, a click on the "Call eval()" button should open a popup dialog containing the Tcl result as its value.</p> <h2>Status</h2> | | | 151 152 153 154 155 156 157 158 159 160 161 | onload="moduleDidLoad();" /> </p> <p>If the module is working correctly, a click on the "Call eval()" button should open a popup dialog containing the Tcl result as its value.</p> <h2>Status</h2> <div id="modstatus">NO-STATUS</div> <hr> </body> </html> |
Changes to nacl/balls.natcl.
|
| | | | < < < < < < < | < | 1 2 3 4 5 6 7 8 9 10 11 | printf BEFORE-TOPLEVEL-SOURCE source a.natcl source b.natcl printf AFTER-TOPLEVEL-SOURCE set cnt 0 proc daemon {} { after 1000 daemon printf DAEMON:$::cnt domset statusField "<h1 align='center'>DAEMON:$::cnt</h1>" |
︙ | ︙ |
Added nacl/c.natcl.
> > | 1 2 | printf "I'm c.natcl" |
Changes to nacl/index.html.
︙ | ︙ | |||
19 20 21 22 23 24 25 | // 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 (tclModule == null) { updateStatus('LOADING...'); | < | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // 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 (tclModule == 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(); } |
︙ | ︙ |
Added nacl/init.natcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #------ Standard NaTcl preamble # core JS/Tcl interaction proc jsquote s { regsub -all {[''\\]} $s {\\&} s regsub -all \n $s {'+"\\n"+'} s return '${s}' } proc bgerror s { printf "### BGERROR: $s" set ::JS "alert([jsquote "BGERROR: $s"]);" } proc naclwrap s { set ::JS "" if {[catch {uplevel 1 $s} err]} { printf "Wrapper error: $err" bgerror $err } return $::JS } # Coro-based [source] necessary for bootstrapping proc source url { set j "tclsource([jsquote $url],[jsquote [info coroutine]]);\n" append ::JS $j set x [yield] uplevel 1 $x } # Async [after] using JS's setTimeout() proc after {ms script} { if {[regexp \n $script]} {error "JS hates multiline :)"} append ::JS "setTimeout(\"tclDo([jsquote $script])\",$ms);\n" } # Delayed DOM-setting through the tclDo() trampoline proc domset {element inner} { append ::JS "$element.innerHTML=[jsquote $inner];\n" } |
Changes to nacl/naclMissing.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | } /* traced */ int access(const char *name, int mode) { printf("*BADSYSCALL:access(\"%s\",%d)\n",name,mode); | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | } /* traced */ int access(const char *name, int mode) { printf("*BADSYSCALL:access(\"%s\",%d)\n",name,mode); // return 0; errno=ENOENT;return -1; } /* plugged */ int _execve (){printf("BADSYSCALL:_execve\n");errno=EINVAL;return -1;} int accept (){printf("BADSYSCALL:accept\n");errno=EINVAL;return -1;} |
︙ | ︙ |