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.
This commit is contained in:
Michael Brown
2007-05-15 16:53:46 +00:00
parent 5471bfbbbe
commit b1755462ab
7 changed files with 96 additions and 38 deletions

View File

@@ -50,6 +50,19 @@ struct downloader {
int ( * register_image ) ( struct image *image );
};
/**
* 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
*
@@ -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;
}