summaryrefslogtreecommitdiffstats
path: root/src/core/image.c
diff options
context:
space:
mode:
authorMichael Brown2009-02-17 01:47:35 +0100
committerMichael Brown2009-02-17 01:47:35 +0100
commit8904cd55f128941d53d9a8beef71fb32a920a92d (patch)
treea2ce11209520f09931d23ccae2682297ada99288 /src/core/image.c
parent[uri] Allow use of relative URIs when calling churi() (diff)
downloadipxe-8904cd55f128941d53d9a8beef71fb32a920a92d.tar.gz
ipxe-8904cd55f128941d53d9a8beef71fb32a920a92d.tar.xz
ipxe-8904cd55f128941d53d9a8beef71fb32a920a92d.zip
[comboot] Allow for tail recursion of COMBOOT images
Multi-level menus via COMBOOT rely on the COMBOOT program being able to exit and invoke a new COMBOOT program (the next menu). This works, but rapidly (within about five iterations) runs out of space in gPXE's internal stack, since each new image is executed in a new function context. Fix by allowing tail recursion between images; an image can now specify a replacement image for itself, and image_exec() will perform the necessary tail recursion.
Diffstat (limited to 'src/core/image.c')
-rw-r--r--src/core/image.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/src/core/image.c b/src/core/image.c
index 440a68c9..741b0547 100644
--- a/src/core/image.c
+++ b/src/core/image.c
@@ -53,6 +53,7 @@ static void free_image ( struct refcnt *refcnt ) {
uri_put ( image->uri );
ufree ( image->data );
+ image_put ( image->replacement );
free ( image );
DBGC ( image, "IMAGE %p freed\n", image );
}
@@ -142,9 +143,9 @@ int register_image ( struct image *image ) {
* @v image Executable/loadable image
*/
void unregister_image ( struct image *image ) {
+ DBGC ( image, "IMAGE %p unregistered\n", image );
list_del ( &image->list );
image_put ( image );
- DBGC ( image, "IMAGE %p unregistered\n", image );
}
/**
@@ -237,6 +238,7 @@ int image_autoload ( struct image *image ) {
* @ret rc Return status code
*/
int image_exec ( struct image *image ) {
+ struct image *replacement;
struct uri *old_cwuri;
int rc;
@@ -257,18 +259,40 @@ int image_exec ( struct image *image ) {
old_cwuri = uri_get ( cwuri );
churi ( image->uri );
+ /* Take out a temporary reference to the image. This allows
+ * the image to unregister itself if necessary, without
+ * automatically freeing itself.
+ */
+ image_get ( image );
+
/* Try executing the image */
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
DBGC ( image, "IMAGE %p could not execute: %s\n",
image, strerror ( rc ) );
- goto done;
+ /* Do not return yet; we still have clean-up to do */
}
- done:
+ /* Pick up replacement image before we drop the original
+ * image's temporary reference.
+ */
+ if ( ( replacement = image->replacement ) != NULL )
+ image_get ( replacement );
+
+ /* Drop temporary reference to the original image */
+ image_put ( image );
+
/* Reset current working directory */
churi ( old_cwuri );
uri_put ( old_cwuri );
+ /* Tail-recurse into replacement image, if one exists */
+ if ( replacement ) {
+ DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
+ image, replacement );
+ if ( ( rc = image_exec ( replacement ) ) != 0 )
+ return rc;
+ }
+
return rc;
}