P-code BINFMT: Add logic to pass information from the binfmt logic to the P-code interpreter. This includes some extension to the binfmt interfaces.

This commit is contained in:
Gregory Nutt 2014-05-08 16:58:10 -06:00
parent 93629d7192
commit e18844de32
11 changed files with 205 additions and 39 deletions

View File

@ -289,7 +289,7 @@ On failure, it returns -1 (<code>ERROR</code>) with <code>errno</code> set appro
<p><b>Function Prototype:</b></p> <p><b>Function Prototype:</b></p>
<ul><pre> <ul><pre>
#include &lt:nuttx/binfmt/binfmt.h&gt; #include &lt:nuttx/binfmt/binfmt.h&gt;
int unload_module(FAR const struct binary_s *bin); int unload_module(FAR struct binary_s *bin);
</pre></ul> </pre></ul>
<p><b>Description:</b></p> <p><b>Description:</b></p>
<ul> <ul>

View File

@ -655,7 +655,7 @@ cat ../syscall/syscall.csv ../libc/lib.csv | sort >tmp.csv
</p> </p>
</ul> </ul>
<p><b><code>int unload_module(FAR const struct binary_s *bin)</code></b> <p><b><code>int unload_module(FAR struct binary_s *bin)</code></b>
<ul> <ul>
<p><b>Description:</b> <p><b>Description:</b>
Unload a (non-executing) module from memory. If the module has Unload a (non-executing) module from memory. If the module has

View File

@ -100,7 +100,9 @@ int dump_module(FAR const struct binary_s *bin)
bdbg(" addrenv: %p\n", bin->addrenv); bdbg(" addrenv: %p\n", bin->addrenv);
#endif #endif
bdbg(" stacksize: %d\n", bin->stacksize); bdbg(" stacksize: %d\n", bin->stacksize);
bdbg(" unload: %p\n", bin->unload);
} }
return OK; return OK;
} }
#endif #endif

View File

@ -72,7 +72,7 @@
* Description: * Description:
* Set the default priority of the module to be loaded. This may be * Set the default priority of the module to be loaded. This may be
* changed (1) by the actions of the binary format's load() method if * changed (1) by the actions of the binary format's load() method if
* the binary format contains priority informaition, or (2) by the user * the binary format contains priority information, or (2) by the user
* between calls to load_module() and exec_module(). * between calls to load_module() and exec_module().
* *
* Returned Value: * Returned Value:
@ -143,6 +143,10 @@ static int load_absmodule(FAR struct binary_s *bin)
/* Successfully loaded -- break out with ret == 0 */ /* Successfully loaded -- break out with ret == 0 */
bvdbg("Successfully loaded module %s\n", bin->filename); bvdbg("Successfully loaded module %s\n", bin->filename);
/* Save the unload method for use by unload_module */
bin->unload = binfmt->unload;
dump_module(bin); dump_module(bin);
break; break;
} }

View File

@ -84,7 +84,7 @@
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_BINFMT_CONSTRUCTORS #ifdef CONFIG_BINFMT_CONSTRUCTORS
static inline int exec_dtors(FAR const struct binary_s *binp) static inline int exec_dtors(FAR struct binary_s *binp)
{ {
binfmt_dtor_t *dtor = binp->dtors; binfmt_dtor_t *dtor = binp->dtors;
#ifdef CONFIG_ADDRENV #ifdef CONFIG_ADDRENV
@ -136,7 +136,7 @@ static inline int exec_dtors(FAR const struct binary_s *binp)
* been started (via exec_module) and has not exited, calling this will * been started (via exec_module) and has not exited, calling this will
* be fatal. * be fatal.
* *
* However, this function must be called after the module exist. How * However, this function must be called after the module exits. How
* this is done is up to your logic. Perhaps you register it to be * this is done is up to your logic. Perhaps you register it to be
* called by on_exit()? * called by on_exit()?
* *
@ -147,18 +147,29 @@ static inline int exec_dtors(FAR const struct binary_s *binp)
* *
****************************************************************************/ ****************************************************************************/
int unload_module(FAR const struct binary_s *binp) int unload_module(FAR struct binary_s *binp)
{ {
#ifdef CONFIG_BINFMT_CONSTRUCTORS
int ret; int ret;
#endif
int i; int i;
if (binp) if (binp)
{ {
/* Execute C++ desctructors */ /* Perform any format-specific unload operations */
if (binp->unload)
{
ret = binp->unload(binp);
if (ret < 0)
{
bdbg("binp->unload() failed: %d\n", ret);
set_errno(-ret);
return ERROR;
}
}
#ifdef CONFIG_BINFMT_CONSTRUCTORS #ifdef CONFIG_BINFMT_CONSTRUCTORS
/* Execute C++ destructors */
ret = exec_dtors(binp); ret = exec_dtors(binp);
if (ret < 0) if (ret < 0)
{ {

View File

@ -72,6 +72,7 @@ static struct binfmt_s g_builtin_binfmt =
{ {
NULL, /* next */ NULL, /* next */
builtin_loadbinary, /* load */ builtin_loadbinary, /* load */
NULL, /* unload */
}; };
/**************************************************************************** /****************************************************************************

View File

@ -95,6 +95,7 @@ static struct binfmt_s g_elfbinfmt =
{ {
NULL, /* next */ NULL, /* next */
elf_loadbinary, /* load */ elf_loadbinary, /* load */
NULL, /* unload */
}; };
/**************************************************************************** /****************************************************************************

View File

@ -91,6 +91,7 @@ static struct binfmt_s g_nxflatbinfmt =
{ {
NULL, /* next */ NULL, /* next */
nxflat_loadbinary, /* load */ nxflat_loadbinary, /* load */
NULL, /* unload */
}; };
/**************************************************************************** /****************************************************************************

View File

@ -47,6 +47,7 @@
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/poff.h> #include <nuttx/poff.h>
#include <nuttx/fs/ramdisk.h> #include <nuttx/fs/ramdisk.h>
#include <nuttx/binfmt/binfmt.h> #include <nuttx/binfmt/binfmt.h>
@ -62,24 +63,28 @@
*/ */
#if CONFIG_NFILE_DESCRIPTORS < 1 #if CONFIG_NFILE_DESCRIPTORS < 1
# error "You must provide file descriptors via CONFIG_NFILE_DESCRIPTORS in your configuration file" # error You must provide file descriptors via CONFIG_NFILE_DESCRIPTORS in your configuration file
#endif #endif
#ifdef CONFIG_BINFMT_DISABLE #ifdef CONFIG_BINFMT_DISABLE
# error "The binary loader is disabled (CONFIG_BINFMT_DISABLE)!" # error The binary loader is disabled (CONFIG_BINFMT_DISABLE)!
#endif #endif
#ifndef CONFIG_PCODE #ifndef CONFIG_PCODE
# error "You must select CONFIG_PCODE in your configuration file" # error You must select CONFIG_PCODE in your configuration file
#endif
#ifndef CONFIG_SCHED_ONEXIT
# error CONFIG_SCHED_ONEXIT is required
#endif #endif
#ifdef CONFIG_PCODE_TEST_FS #ifdef CONFIG_PCODE_TEST_FS
# ifndef CONFIG_FS_ROMFS # ifndef CONFIG_FS_ROMFS
# error "You must select CONFIG_FS_ROMFS in your configuration file" # error You must select CONFIG_FS_ROMFS in your configuration file
# endif # endif
# ifdef CONFIG_DISABLE_MOUNTPOINT # ifdef CONFIG_DISABLE_MOUNTPOINT
# error "You must not disable mountpoints via CONFIG_DISABLE_MOUNTPOINT in your configuration file" # error You must not disable mountpoints via CONFIG_DISABLE_MOUNTPOINT in your configuration file
# endif # endif
# ifndef CONFIG_PCODE_TEST_DEVMINOR # ifndef CONFIG_PCODE_TEST_DEVMINOR
@ -104,7 +109,19 @@
* Private Function Prototypes * Private Function Prototypes
****************************************************************************/ ****************************************************************************/
static int pcode_loadbinary(FAR struct binary_s *binp); struct binfmt_handoff_s
{
sem_t exclsem; /* Supports mutually exclusive access */
FAR struct binary_s *binp; /* Binary format being handed off */
FAR char *fullpath; /* Full path to the P-Code file */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int pcode_load(FAR struct binary_s *binp);
static int pcode_unload(FAR struct binary_s *binp);
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
@ -112,10 +129,13 @@ static int pcode_loadbinary(FAR struct binary_s *binp);
static struct binfmt_s g_pcode_binfmt = static struct binfmt_s g_pcode_binfmt =
{ {
NULL, /* next */ NULL, /* next */
pcode_loadbinary, /* load */ pcode_load, /* load */
pcode_unload, /* unload */
}; };
struct binfmt_handoff_s g_pcode_handoff;
#ifdef CONFIG_PCODE_TEST_FS #ifdef CONFIG_PCODE_TEST_FS
# include "romfs.h" # include "romfs.h"
#endif #endif
@ -181,17 +201,70 @@ static int pcode_mount_testfs(void)
#endif #endif
/**************************************************************************** /****************************************************************************
* Name: pcode_proxy * Name: pcode_onexit
* *
* Description: * Description:
* This is the proxy program that runs and starts the P-Code interpreter. * This is the proxy program that runs and starts the P-Code interpreter.
* *
****************************************************************************/ ****************************************************************************/
#ifndef CONFIG_NUTTX_KERNEL
static void pcode_onexit(int exitcode, FAR void *arg)
{
FAR struct binary_s *binp = (FAR struct binary_s *)arg;
DEBUGASSERT(binp);
/* And unload the module */
unload_module(binp);
}
#endif
/****************************************************************************
* Name: pcode_proxy
*
* Description:
* This is the proxy program that runs and starts the P-Code interpreter.
*
* REVISIT: There are issues here when CONFIG_NUTTX_KERNEL is selected.
*
****************************************************************************/
#ifndef CONFIG_NUTTX_KERNEL #ifndef CONFIG_NUTTX_KERNEL
static int pcode_proxy(int argc, char **argv) static int pcode_proxy(int argc, char **argv)
{ {
/* REVISIT: There are issues here when CONFIG_NUTTX_KERNEL is selected. */ FAR struct binary_s *binp;
FAR char *fullpath;
int ret;
/* Get the struct binary_s instance from the handoff structure */
binp = g_pcode_handoff.binp;
g_pcode_handoff.binp = NULL;
fullpath = g_pcode_handoff.fullpath;
g_pcode_handoff.fullpath = NULL;
sem_post(&g_pcode_handoff.exclsem);
DEBUGASSERT(binp && fullpath);
bvdbg("Executing %s\n", fullpath);
/* Set-up the on-exit handler that will unload the module on exit */
ret = on_exit(pcode_onexit, binp);
if (ret < 0)
{
bdbg("ERROR: on_exit failed: %d\n", errno);
return EXIT_FAILURE;
}
/* Load the P-code file and execute it */
/* We don't need the fullpath now */
kfree(fullpath);
/* Execute the P-code file and execute it */
bdbg("ERROR: Not implemented\n"); bdbg("ERROR: Not implemented\n");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -201,14 +274,14 @@ static int pcode_proxy(int argc, char **argv)
#endif #endif
/**************************************************************************** /****************************************************************************
* Name: pcode_loadbinary * Name: pcode_load
* *
* Description: * Description:
* Verify that the file is an pcode binary. * Verify that the file is a pcode binary.
* *
****************************************************************************/ ****************************************************************************/
static int pcode_loadbinary(struct binary_s *binp) static int pcode_load(struct binary_s *binp)
{ {
FAR struct poff_fileheader_s hdr; FAR struct poff_fileheader_s hdr;
FAR uint8_t *ptr; FAR uint8_t *ptr;
@ -262,7 +335,7 @@ static int pcode_loadbinary(struct binary_s *binp)
DEBUGASSERT(nread > 0 && nread <=remaining); DEBUGASSERT(nread > 0 && nread <=remaining);
remaining -= nread; remaining -= nread;
ptr += nread; ptr += nread;
} }
} }
#ifdef CONFIG_PCODE_DUMPBUFFER #ifdef CONFIG_PCODE_DUMPBUFFER
@ -286,7 +359,36 @@ static int pcode_loadbinary(struct binary_s *binp)
binp->stacksize = CONFIG_PCODE_STACKSIZE; binp->stacksize = CONFIG_PCODE_STACKSIZE;
binp->priority = CONFIG_PCODE_PRIORITY; binp->priority = CONFIG_PCODE_PRIORITY;
/* Successfully identified a p-code binary */ /* Get exclusive access to the p-code handoff structure */
do
{
ret = sem_wait(&g_pcode_handoff.exclsem);
DEBUGASSERT(ret == OK || errno == EINTR);
}
while (ret < 0);
/* Save the data that we need to handoff to the child thread */
DEBUGASSERT(g_pcode_handoff.binp == NULL &&
g_pcode_handoff.fullpath == NULL);
/* Duplicate the full path to the binary */
g_pcode_handoff.fullpath = strdup(binp->filename);
if (!g_pcode_handoff.fullpath)
{
bdbg("ERROR: Failed to duplicate the full path: %d\n",
binp->filename);
sem_post(&g_pcode_handoff.exclsem);
ret = -ENOMEM;
goto errout_with_fd;
}
g_pcode_handoff.binp = binp;
/* Successfully identified (but not really loaded) a p-code binary */
ret = OK; ret = OK;
@ -295,6 +397,29 @@ errout_with_fd:
return ret; return ret;
} }
/****************************************************************************
* Name: pcode_unload
*
* Description:
* Called when the pcode binary is unloaded. This is necessary primarily
* to handler error conditions where unload_module is called after
* pcode_load without having executed the P-Code module.
*
****************************************************************************/
static int pcode_unload(struct binary_s *binp)
{
/* Increment the semaphore count back to one if appropriate */
if (g_pcode_handoff.binp)
{
g_pcode_handoff.binp = NULL;
sem_post(&g_pcode_handoff.exclsem);
}
return OK;
}
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
@ -318,6 +443,10 @@ int pcode_initialize(void)
{ {
int ret; int ret;
/* Initialize globals */
sem_init(&g_pcode_handoff.exclsem, 0, 1);
/* Mount the test file system */ /* Mount the test file system */
ret = pcode_mount_testfs(); ret = pcode_mount_testfs();
@ -378,6 +507,10 @@ void pcode_uninitialize(void)
UNUSED(errval); UNUSED(errval);
} }
#endif #endif
/* Uninitialize globals */
sem_destroy(&g_pcode_handoff.exclsem);
} }
#endif /* CONFIG_PCODE */ #endif /* CONFIG_PCODE */

View File

@ -136,14 +136,27 @@ struct binary_s
uint8_t priority; /* Task execution priority */ uint8_t priority; /* Task execution priority */
size_t stacksize; /* Size of the stack in bytes (unallocated) */ size_t stacksize; /* Size of the stack in bytes (unallocated) */
/* Unload module callback */
CODE int (*unload)(FAR struct binary_s *bin);
}; };
/* This describes one binary format handler */ /* This describes one binary format handler */
struct binfmt_s struct binfmt_s
{ {
FAR struct binfmt_s *next; /* Supports a singly-linked list */ /* Supports a singly-linked list */
int (*load)(FAR struct binary_s *bin); /* Verify and load binary into memory */
FAR struct binfmt_s *next;
/* Verify and load binary into memory */
CODE int (*load)(FAR struct binary_s *bin);
/* Unload module callback */
CODE int (*unload)(FAR struct binary_s *bin);
}; };
/**************************************************************************** /****************************************************************************
@ -224,7 +237,7 @@ int load_module(FAR struct binary_s *bin);
* *
****************************************************************************/ ****************************************************************************/
int unload_module(FAR const struct binary_s *bin); int unload_module(FAR struct binary_s *bin);
/**************************************************************************** /****************************************************************************
* Name: exec_module * Name: exec_module

View File

@ -47,7 +47,8 @@
#ifdef __cplusplus #ifdef __cplusplus
#define EXTERN extern "C" #define EXTERN extern "C"
extern "C" { extern "C"
{
#else #else
#define EXTERN extern #define EXTERN extern
#endif #endif
@ -126,17 +127,16 @@ struct timespec; /* Defined in time.h */
/* Counting Semaphore Interfaces (based on POSIX APIs) */ /* Counting Semaphore Interfaces (based on POSIX APIs) */
EXTERN int sem_init(FAR sem_t *sem, int pshared, unsigned int value); int sem_init(FAR sem_t *sem, int pshared, unsigned int value);
EXTERN int sem_destroy(FAR sem_t *sem); int sem_destroy(FAR sem_t *sem);
EXTERN FAR sem_t *sem_open(FAR const char *name, int oflag, ...); FAR sem_t *sem_open(FAR const char *name, int oflag, ...);
EXTERN int sem_close(FAR sem_t *sem); int sem_close(FAR sem_t *sem);
EXTERN int sem_unlink(FAR const char *name); int sem_unlink(FAR const char *name);
EXTERN int sem_wait(FAR sem_t *sem); int sem_wait(FAR sem_t *sem);
EXTERN int sem_timedwait(FAR sem_t *sem, int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime);
FAR const struct timespec *abstime); int sem_trywait(FAR sem_t *sem);
EXTERN int sem_trywait(FAR sem_t *sem); int sem_post(FAR sem_t *sem);
EXTERN int sem_post(FAR sem_t *sem); int sem_getvalue(FAR sem_t *sem, FAR int *sval);
EXTERN int sem_getvalue(FAR sem_t *sem, FAR int *sval);
#undef EXTERN #undef EXTERN
#ifdef __cplusplus #ifdef __cplusplus