diff mbox

Add cleanup routines.

Message ID A521BD06-7228-4FA9-97DD-7DFA51BE7505@gmx.net (mailing list archive)
State Rejected
Headers show

Commit Message

Hannes Weisbach April 11, 2014, 4:50 p.m. UTC
Dynamically loaded library handles are saved in a list and dlclosed() on
exit. The list of struct ibv_driver *, as well as the global
struct ibv_device ** list are free()d.

Signed-off-by: Hannes Weisbach <hannes_weisbach@gmx.net>
---
 src/device.c | 10 ++++++++++
 src/init.c   | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 56 insertions(+), 5 deletions(-)

Comments

Yann Droneaud April 11, 2014, 5 p.m. UTC | #1
Hi,

Le vendredi 11 avril 2014 à 18:50 +0200, Hannes Weisbach a écrit :
> Dynamically loaded library handles are saved in a list and dlclosed() on
> exit. The list of struct ibv_driver *, as well as the global
> struct ibv_device ** list are free()d.
> 

Please adds some explanation, in particular the purpose of the changes.
Your commit message only explain "how", but you should also explain
"why".

> Signed-off-by: Hannes Weisbach <hannes_weisbach@gmx.net>
> ---
>  src/device.c | 10 ++++++++++
>  src/init.c   | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
>  2 files changed, 56 insertions(+), 5 deletions(-)
> 
> diff --git a/src/device.c b/src/device.c
> index beb7b3c..d5b76bb 100644
> --- a/src/device.c
> +++ b/src/device.c
> @@ -305,3 +305,13 @@ void __ibv_ack_async_event(struct ibv_async_event *event)
>  	}
>  }
>  default_symver(__ibv_ack_async_event, ibv_ack_async_event);
> +
> +FINI static void ibverbs_deinit()

In C, empty prototype declare a function which accept any parameter. So
perhaps void ibverbs(void) is what you mean.

> +{
> +	size_t i;
> +	for (i = 0; i < num_devices; i++) {
> +		/* driver callback needed. May not be malloc'd memory */

Seems dangerous. Such interrogation must be explicitly added in the
commit message. 

> +		free(device_list[i]);
> +	}
> +	free(device_list);
> +}
> diff --git a/src/init.c b/src/init.c
> index d0e4b1c..2a8bca4 100644
> --- a/src/init.c
> +++ b/src/init.c
> @@ -67,6 +67,11 @@ struct ibv_driver_name {
>  	struct ibv_driver_name *next;
>  };
>  
> +struct ibv_so_list {
> +	void *dlhandle;
> +	struct ibv_so_list *next;
> +};
> +
>  struct ibv_driver {
>  	const char	       *name;
>  	ibv_driver_init_func	init_func;
> @@ -77,6 +82,7 @@ struct ibv_driver {
>  static struct ibv_sysfs_dev *sysfs_dev_list;
>  static struct ibv_driver_name *driver_name_list;
>  static struct ibv_driver *head_driver, *tail_driver;
> +static struct ibv_so_list *so_list;
>  
>  static int find_sysfs_devs(void)
>  {
> @@ -193,7 +199,14 @@ void verbs_register_driver(const char *name, verbs_driver_init_func init_func)
>  static void load_driver(const char *name)
>  {
>  	char *so_name;
> -	void *dlhandle;
> +	struct ibv_so_list *elem;
> +	struct ibv_so_list **list;
> +
> +	elem = malloc(sizeof(*elem));
> +	if(!elem)
> +		return;
> +
> +	elem->next = NULL;
>  
>  #define __IBV_QUOTE(x)	#x
>  #define IBV_QUOTE(x)	__IBV_QUOTE(x)
> @@ -205,16 +218,25 @@ static void load_driver(const char *name)
>  		     name) < 0) {
>  		fprintf(stderr, PFX "Warning: couldn't load driver '%s'.\n",
>  			name);
> -		return;
> +		goto err;
>  	}
>  
> -	dlhandle = dlopen(so_name, RTLD_NOW);
> -	if (!dlhandle) {
> +	elem->dlhandle = dlopen(so_name, RTLD_NOW);
> +	if (!elem->dlhandle) {
>  		fprintf(stderr, PFX "Warning: couldn't load driver '%s': %s\n",
>  			name, dlerror());
> -		goto out;
> +		goto err;
>  	}
>  
> +	for (list = &so_list; *list; list = &(*list)->next)
> +		;
> +
> +	*list = elem;
> +
> +	goto out;
> +
> +err:
> +	free(elem);
>  out:
>  	free(so_name);
>  }
> @@ -573,3 +595,22 @@ out:
>  
>  	return num_devices;
>  }
> +
> +FINI static void unload_drivers()

same remarks about prototype.

> +{
> +	struct ibv_driver *driver;
> +	struct ibv_so_list * list;
> +
> +	for (driver = head_driver; driver;) {
> +		struct ibv_driver *tmp = driver;
> +		driver = driver->next;
> +		free(tmp);
> +	}
> +

Is it safe here to free the driver ?

> +	for (list = so_list; list;) {
> +		struct ibv_so_list *tmp = list;
> +		list = list->next;
> +		dlclose(tmp->dlhandle);
> +		free(tmp);
> +	}
> +}

Why not store the dlopen() handle in the struct ibv_driver itself ?
This way only one list has to be scanned.

Regards.
Hannes Weisbach April 11, 2014, 5:46 p.m. UTC | #2
Am 11.04.2014 um 19:00 schrieb Yann Droneaud <ydroneaud@opteya.com>:

> Hi,
Thanks for your quick reply.

> Please adds some explanation, in particular the purpose of the changes.
> Your commit message only explain "how", but you should also explain
> "why".
Ok.

> In C, empty prototype declare a function which accept any parameter. So
> perhaps void ibverbs(void) is what you mean.
Yup, thanks.

>> +{
>> +	size_t i;
>> +	for (i = 0; i < num_devices; i++) {
>> +		/* driver callback needed. May not be malloc'd memory */
> 
> Seems dangerous. Such interrogation must be explicitly added in the
> commit message. 
Maybe it's better to leave it as a TODO and only free the device_list
itself?

>> +	for (driver = head_driver; driver;) {
>> +		struct ibv_driver *tmp = driver;
>> +		driver = driver->next;
>> +		free(tmp);
>> +	}
>> +
> 
> Is it safe here to free the driver ?
The struct itself is no longer needed.  All the driver libraries are
loaded and ibverbs_init() is call-once, so no new libraries are
dlopen()ed (and call ibv_register_driver()).
It's probably nicer first to dlclose() all libraries and then free all
struct ibv_drivers.

>> +	for (list = so_list; list;) {
>> +		struct ibv_so_list *tmp = list;
>> +		list = list->next;
>> +		dlclose(tmp->dlhandle);
>> +		free(tmp);
>> +	}
>> +}
> 
> Why not store the dlopen() handle in the struct ibv_driver itself ?
> This way only one list has to be scanned.
That was my first idea, but the struct ibv_driver doesn't exist at
that time.  First the (driver) library is dlopen()d and calls
ibv_register_driver().  Only there is the ibv_driver struct allocated,
but the handle is gone.

Best regards,
Hannes
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/src/device.c b/src/device.c
index beb7b3c..d5b76bb 100644
--- a/src/device.c
+++ b/src/device.c
@@ -305,3 +305,13 @@  void __ibv_ack_async_event(struct ibv_async_event *event)
 	}
 }
 default_symver(__ibv_ack_async_event, ibv_ack_async_event);
+
+FINI static void ibverbs_deinit()
+{
+	size_t i;
+	for (i = 0; i < num_devices; i++) {
+		/* driver callback needed. May not be malloc'd memory */
+		free(device_list[i]);
+	}
+	free(device_list);
+}
diff --git a/src/init.c b/src/init.c
index d0e4b1c..2a8bca4 100644
--- a/src/init.c
+++ b/src/init.c
@@ -67,6 +67,11 @@  struct ibv_driver_name {
 	struct ibv_driver_name *next;
 };
 
+struct ibv_so_list {
+	void *dlhandle;
+	struct ibv_so_list *next;
+};
+
 struct ibv_driver {
 	const char	       *name;
 	ibv_driver_init_func	init_func;
@@ -77,6 +82,7 @@  struct ibv_driver {
 static struct ibv_sysfs_dev *sysfs_dev_list;
 static struct ibv_driver_name *driver_name_list;
 static struct ibv_driver *head_driver, *tail_driver;
+static struct ibv_so_list *so_list;
 
 static int find_sysfs_devs(void)
 {
@@ -193,7 +199,14 @@  void verbs_register_driver(const char *name, verbs_driver_init_func init_func)
 static void load_driver(const char *name)
 {
 	char *so_name;
-	void *dlhandle;
+	struct ibv_so_list *elem;
+	struct ibv_so_list **list;
+
+	elem = malloc(sizeof(*elem));
+	if(!elem)
+		return;
+
+	elem->next = NULL;
 
 #define __IBV_QUOTE(x)	#x
 #define IBV_QUOTE(x)	__IBV_QUOTE(x)
@@ -205,16 +218,25 @@  static void load_driver(const char *name)
 		     name) < 0) {
 		fprintf(stderr, PFX "Warning: couldn't load driver '%s'.\n",
 			name);
-		return;
+		goto err;
 	}
 
-	dlhandle = dlopen(so_name, RTLD_NOW);
-	if (!dlhandle) {
+	elem->dlhandle = dlopen(so_name, RTLD_NOW);
+	if (!elem->dlhandle) {
 		fprintf(stderr, PFX "Warning: couldn't load driver '%s': %s\n",
 			name, dlerror());
-		goto out;
+		goto err;
 	}
 
+	for (list = &so_list; *list; list = &(*list)->next)
+		;
+
+	*list = elem;
+
+	goto out;
+
+err:
+	free(elem);
 out:
 	free(so_name);
 }
@@ -573,3 +595,22 @@  out:
 
 	return num_devices;
 }
+
+FINI static void unload_drivers()
+{
+	struct ibv_driver *driver;
+	struct ibv_so_list * list;
+
+	for (driver = head_driver; driver;) {
+		struct ibv_driver *tmp = driver;
+		driver = driver->next;
+		free(tmp);
+	}
+
+	for (list = so_list; list;) {
+		struct ibv_so_list *tmp = list;
+		list = list->next;
+		dlclose(tmp->dlhandle);
+		free(tmp);
+	}
+}