FP Final Update ( By bnext Last mod: Jun 10 16:44 )
I have done a snapshot of my code in a tar.gz file, I don't know how to upload this snapshot so I have copied this to my home dir in gsoc.cat-v.org.
Finally I have not success with the planning I'd done. Actually the plugin loads and runs libinit and emuinit, but fails while running disinit. I have translated the thread management to pthread, and the problem happens about the exception and error handler, I have problems when calling waserror(), I've seen in the IE plugin that it changes the exception handler, I think that I might do the same but I'm not sure about it.
The error that I had with the free calls is solved, I was using the __clone proc to create threads, now I use pthread_create and it seems to solve the problem, now I have core dumps of the errors and I can use it to solve the problems.
About the other goals of the project the status is:
- Dis files to execute: It's easy to transfer files from Mozilla to the plugin, so I can use it to load a dis file into the plugin and run it, I don't know if I can use the dis file as the imod parameter of the emuinit in order to execute this. I have test this with others files like jpgs in order to load the image in the plugin window.
- Keyboard: I know how to use the keyboard input, only I have to midify the readkbd function to let the firefox-os.c manage the keyboard input.
Graphics: The plugins uses X11 to manage graphics, so I can use the same graphics management of Linux emu.
I will continue with the project development till the end regardless of the final evaluation of the gsoc.
FP update ( By bnext Last mod: Jun 10 16:44 )
Process management is all right. I have used pthreads in order to execute inferno's main in a thread while the main thread still runs as a plugin. Emuinit loads, but Firefox crashes when the ksetenv function is called, now I have comment the calls to ksetenv. A proc is created to execute disinit, I'm trying to trace if this disinit is running ok. Kproc works and everything seems to be ok but ksetenvs.
Then I will work in the console, I want to let emu paint the console in the firefox window (using X11), I hope to achieve it tomorrow.
FIREFOX PLUGIN UPDATE ( By bnext Last mod: Jun 10 16:44 )
Inferno Plugin update
I have had many problems with the memory management due to the fact that the plugin is loaded as a shared library. This implies that when the inferno code calls to malloc/free/realloc it calls the malloc/free/realloc functions from libc instead the malloc/free/realloc functions defined in alloc.c. This happens because the plugin is a shared library, and when the inferno code calls malloc, it finds the libc malloc before the inferno's malloc redefinition, idem with free and realloc.
In order to solve this issue I renamed malloc, free and realloc from alloc.c to imalloc, ifree and irealloc, writing the preprocessor directives in fns.h:
#define malloc(s) imalloc(s)
#define free(l) ifree(l)
#define realloc(v,s) irealloc(v,s)
But this result in another problem, there are calls to ifree where its argument is not a memory reference reserved by imalloc, and when it tries to free this memory an "not in pools" error ocurrs. In order to find where there is ifree calls to free memory reserved by libc malloc instead inferno imalloc I have used the ElectricFence library (thanks Chris), putting it in the LD_PRELOAD path so any call to malloc/free will call the malloc/free of EF, this way I have found (after many problems) the ifree call culprit of the problem. This call was inside the kstrdup function, the above mentioned function is that:
void
kstrdup(char **p, char *s)
{
int n;
char *t, *prev;
n = strlen(s)+1;
t = kmalloc(n);
if(t == nil)
panic("kstrdup: no memory");
memmove(t, s, n);
prev = *p;
*p = t;
free(prev);
}
You can notice that at the end of the kstrdup function it calls to free(prev) (that finally is ifree(prev)), where 'prev' contains the last content of the reference that now references to the string copy 's'. The problems comes when the above mentioned pointer has not been initialized and does not contain memory reserved by imalloc but libc malloc. This happens with the string 'eve' which is initialized in main() (main.c) by calling strdup (libc), internally strdup calls libc malloc, then eve's memory has been reserved by glib malloc not inferno's imalloc, nevertheless, in libinit() eve's content is changed by calling kstrdup(eve,"newstring"), and when it tries to free the previous content of eve it try to free it calling ifree (when it was reserved by libc's malloc not inferno malloc).
To solve this issue I have wrote a strdup redefinition named istrdup that does the same that standard strdup but calling imalloc instead libc's malloc.
In addition, inferno code calls to sbrk to get for memory from the host OS to allow that inferno manages this memory. To be able to reserve memory acting as a plugin it is necessary to to call to NPN_MemAlloc() (Mozilla NPAPI) so I have added a redefinition of sbrk named isbrk that gives memory to inferno using Mozilla's API. In order to let the plugin use istrdup/isbrk instead of strdup/sbrk of libc I have added other directives to fns.h:
#define strdup(s) istrdup(s)
#define sbrk(s) isbrk(s)
With this the problem of the memory management seems to be solved (for the present).
Process Management
Mozilla Firefox API for Plugins does not offer functions to create and manage process or threads, so it is possible to use directly the same calls for the process creation in Linux. Nowadays I have tried to create processes with kproc and it seems that everything is alright.
Nowadays Status
The problem that I have now is with the calls to ksetenv, when ksetenv is called in emuinit Firefox crash, and the only thing that says is "Firefox: Unknown error 2988458393", I have traced the calls and it seems that ksetenv (env.c) calls to namec() (chan.c), the flow enters the switch(amode) statement and go to the branch 'Acreate' where it calls to walk() and gives the error.
If I comment the ksetenv call, then emuinit runs without problems, but emuinit is called from libinit by:
executeonnewstack(tos, emuinit, imod);
But after this statement nothing statement is executed, so the 'for' iteration of the end of emuinit will keep the control of the main plugin process, and then the plugin does not respond neither offer the NPP functins that Mozilla needs. Then the plugin does not respond to the browser requests and finally crash. The plugin must offer many NPP functions in order to comunicate with Firefox, one of these function is NPP_Init where the plugin initialices and where I have added the call to ipluginmain() (firefox-os.c) that is the entry point to inferno from the plugin.
Maybe a possible solution to this is to create a new independent process where execute ipluginmain while the main process remains running and receiving browser requests...
Planning:
I have this aims:
- Memory initialization
- Threads/proccess initialization
- console
- "Hello world"
- text input (console, but keyboard)
- graphics and mouse events
- cleaning
Memory initialization semms to be solved, process initialization seems to work but it could cause problems, emuinit does not load right due to the ksetenv problem, when I solve this I hope to have an initialized and running inferno.
The next steps are:
Console: Paint the console (emu running) -> On August 14 Hello Worlds: execute a simple "hello world" within the console -> On August 15 Text Input by keyboard to feed the console -> On August 17 Paint graphics and handle mouse events -> On August 22 Clean the code -> On August 25
Please any comments will be welcome.
Thanks.
Now what ( By bnext Last mod: Jun 10 16:44 )
Once I have a plugin structured program I have to load the VM with it. In order to do it I've written a 'firefox' configuration file, it's a copy of 'emu' configuration file but I've modified it introducing the flags and path's (include's) that it needs to compile inferno as a plugin. First I modify the mkfile and write a new variable "PLUG", then I put this new variable in the compilation objectives (OBJ variable), I put the 'firefox' config file in the CONFLIST, and I redefine the PLUG variable in 'firefox' so that PLUG point to the plugin structure code files. Then I have a shared object lib of 5 MB where the emu VM and the plugin structured program live together.
Now Mozilla can use this lib, and the plugin loads, on the other hand, emu is not running, it's only loaded but not running.
I could try to run emu writing a mainplugin procedure which is called from the plugin init cycle. This mainplugin would call libinit procedure in order to let run the VM. But, it will never success, because my emu is not living under Linux but under Mozilla, and it must adapt to the Mozilla API, it's like Mozilla is the host OS.
But first let me talk about the inferno init model...
Lets talk about plugins ( By bnext Last mod: Jun 10 16:44 )
Ok, let's talk about plugins,
Firefox plugins are written using the NPAPI (Gecko Plugin API: http://developer.mozilla.org/en/docs/GeckoPluginAPIReference), Mozilla provides an SDK and API in order to let programmers who want to build plugins build it without needing of the entire mozilla source code tree, you can get it here (http://developer.mozilla.org/en/docs/GeckoSDK). there are a lot of documentation right there, however most of these docs are incomplete. You can find examples and tests of using the npapi (http://developer.mozilla.org/en/docs/Plugins:SamplesandTestCases).
If I have to be honest, I couldn't even compile these examples without errors, I don't know if I'm a little bit clumsy... Then, what did I do? Well, the npapi is in C++ with O.O. and I want C pure, then I get the SDK and I write my own NPAPI interface, I write a C version of the needed files, based on the Gecko Plugin API Reference.
I wrote two files, "npngate.c" and "nppgate.c", these files come from the Plugin Side Plugin API, and from the Browser Side Plugin API respectively.
When you have a Plugin you need two things, first your plugin has to provide a minimal set of functions in order to let Firefox talk with him, these functions are defined in the file "nppgate.c", and in the other hand your plugin has to define the interface to communicate with netscape functions, in the file "npngate.c" there are wrapper function for the Browser Side API, and there is the function that fills the Plugin and Browser Side functions table. These two files include the npapi.h (from the NPAPI SDK) where you can find all the functions that must be implemented.
If your plugin code includes these two files Mozilla will recognise it as a valid plugin.
First time ( By bnext Last mod: Jun 10 16:44 )
Hi people!
I'm here, at last. Well, I'm Bnext and I'm building the Inferno Plugin for Mozilla Firefox (IPMF), from now on I hope to update the blog entries daily.
I've uploaded my first code delivery ;)
Ok, that's all, will go to the code :P