summaryrefslogtreecommitdiffstats
path: root/src/core/downloader.c
diff options
context:
space:
mode:
authorMichael Brown2007-05-15 18:53:46 +0200
committerMichael Brown2007-05-15 18:53:46 +0200
commitb1755462ab344ff758c3a1e6ae0d10a729d96d1b (patch)
tree858bb7ba3d439be957f6b9530a0040b26c49f3f2 /src/core/downloader.c
parentData-transfer interface should now be functionally complete. (diff)
downloadipxe-b1755462ab344ff758c3a1e6ae0d10a729d96d1b.tar.gz
ipxe-b1755462ab344ff758c3a1e6ae0d10a729d96d1b.tar.xz
ipxe-b1755462ab344ff758c3a1e6ae0d10a729d96d1b.zip
Do not hold self-references. This then avoids the problem of having to
ensure that we only drop our self-reference exactly once. To maintain the guarantee that an object won't go out of scope unexpectedly while one of its event handlers is being called, the event-calling functions now automatically obtain and drop extra references.
Diffstat (limited to 'src/core/downloader.c')
-rw-r--r--src/core/downloader.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/src/core/downloader.c b/src/core/downloader.c
index 2e466cbf..653a4806 100644
--- a/src/core/downloader.c
+++ b/src/core/downloader.c
@@ -51,6 +51,19 @@ struct downloader {
};
/**
+ * Free downloader object
+ *
+ * @v refcnt Downloader reference counter
+ */
+static void downloader_free ( struct refcnt *refcnt ) {
+ struct downloader *downloader =
+ container_of ( refcnt, struct downloader, refcnt );
+
+ image_put ( downloader->image );
+ free ( downloader );
+}
+
+/**
* Terminate download
*
* @v downloader Downloader
@@ -63,12 +76,8 @@ static void downloader_finished ( struct downloader *downloader, int rc ) {
xfer_nullify ( &downloader->xfer );
/* Free resources and close interfaces */
- image_put ( downloader->image );
xfer_close ( &downloader->xfer, rc );
job_done ( &downloader->job, rc );
-
- /* Drop reference to self */
- ref_put ( &downloader->refcnt );
}
/**
@@ -267,6 +276,7 @@ int create_downloader ( struct job_interface *job, const char *uri_string,
if ( ! downloader )
return -ENOMEM;
memset ( downloader, 0, sizeof ( *downloader ) );
+ downloader->refcnt.free = downloader_free;
job_init ( &downloader->job, &downloader_job_operations,
&downloader->refcnt );
xfer_init ( &downloader->xfer, &downloader_xfer_operations,
@@ -279,11 +289,13 @@ int create_downloader ( struct job_interface *job, const char *uri_string,
uri_string ) ) != 0 )
goto err;
- /* Attach parent interface and return */
+ /* Attach parent interface, mortalise self, and return */
job_plug_plug ( &downloader->job, job );
+ ref_put ( &downloader->refcnt );
return 0;
err:
downloader_finished ( downloader, rc );
+ ref_put ( &downloader->refcnt );
return rc;
}