FIX: Introduced destroy() functions for kobject-derived classes and thus fixed memory leak.
--- a/master/canopen.c Thu Oct 26 16:45:33 2006 +0000
+++ b/master/canopen.c Fri Oct 27 09:19:58 2006 +0000
@@ -132,19 +132,35 @@
/**
SDO destructor.
-*/
-
-void ec_sdo_clear(struct kobject *kobj /**< SDO's kobject */)
-{
- ec_sdo_t *sdo = container_of(kobj, ec_sdo_t, kobj);
+ Clears and frees an SDO object.
+*/
+
+void ec_sdo_destroy(ec_sdo_t *sdo /**< SDO */)
+{
ec_sdo_entry_t *entry, *next;
// free all entries
list_for_each_entry_safe(entry, next, &sdo->entries, list) {
list_del(&entry->list);
- kobject_del(&entry->kobj);
- kobject_put(&entry->kobj);
- }
+ ec_sdo_entry_destroy(entry);
+ }
+
+ // destroy self
+ kobject_del(&sdo->kobj);
+ kobject_put(&sdo->kobj);
+}
+
+/*****************************************************************************/
+
+/**
+ Clear and free SDO.
+ This method is called by the kobject,
+ once there are no more references to it.
+*/
+
+void ec_sdo_clear(struct kobject *kobj /**< SDO's kobject */)
+{
+ ec_sdo_t *sdo = container_of(kobj, ec_sdo_t, kobj);
if (sdo->name) kfree(sdo->name);
@@ -215,7 +231,23 @@
/*****************************************************************************/
/**
- SDO destructor.
+ SDO entry destructor.
+ Clears and frees an SDO entry object.
+*/
+
+void ec_sdo_entry_destroy(ec_sdo_entry_t *entry /**< SDO entry */)
+{
+ // destroy self
+ kobject_del(&entry->kobj);
+ kobject_put(&entry->kobj);
+}
+
+/*****************************************************************************/
+
+/**
+ Clear and free SDO entry.
+ This method is called by the kobject,
+ once there are no more references to it.
*/
void ec_sdo_entry_clear(struct kobject *kobj /**< SDO entry's kobject */)
--- a/master/canopen.h Thu Oct 26 16:45:33 2006 +0000
+++ b/master/canopen.h Fri Oct 27 09:19:58 2006 +0000
@@ -120,7 +120,10 @@
/*****************************************************************************/
int ec_sdo_init(ec_sdo_t *, uint16_t, ec_slave_t *);
+void ec_sdo_destroy(ec_sdo_t *);
+
int ec_sdo_entry_init(ec_sdo_entry_t *, uint8_t, ec_sdo_t *);
+void ec_sdo_entry_destroy(ec_sdo_entry_t *);
/*****************************************************************************/
--- a/master/domain.c Thu Oct 26 16:45:33 2006 +0000
+++ b/master/domain.c Fri Oct 27 09:19:58 2006 +0000
@@ -130,6 +130,30 @@
/**
Domain destructor.
+ Clears and frees a domain object.
+*/
+
+void ec_domain_destroy(ec_domain_t *domain /**< EtherCAT domain */)
+{
+ ec_datagram_t *datagram;
+
+ // dequeue datagrams
+ list_for_each_entry(datagram, &domain->datagrams, list) {
+ if (!list_empty(&datagram->queue)) // datagram queued?
+ list_del_init(&datagram->queue);
+ }
+
+ // destroy self
+ kobject_del(&domain->kobj);
+ kobject_put(&domain->kobj);
+}
+
+/*****************************************************************************/
+
+/**
+ Clear and free domain.
+ This method is called by the kobject,
+ once there are no more references to it.
*/
void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */)
@@ -464,22 +488,6 @@
/*****************************************************************************/
/**
- Dequeues all datagrams from the masters datagram queue.
-*/
-
-void ec_domain_dequeue_datagrams(ec_domain_t *domain /**< EtherCAT domain */)
-{
- ec_datagram_t *datagram;
-
- list_for_each_entry(datagram, &domain->datagrams, list) {
- if (!list_empty(&datagram->queue)) // datagram queued?
- list_del_init(&datagram->queue);
- }
-}
-
-/*****************************************************************************/
-
-/**
Formats attribute data for SysFS reading.
\return number of bytes to read
*/
--- a/master/domain.h Thu Oct 26 16:45:33 2006 +0000
+++ b/master/domain.h Fri Oct 27 09:19:58 2006 +0000
@@ -76,11 +76,10 @@
/*****************************************************************************/
int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int);
+void ec_domain_destroy(ec_domain_t *);
int ec_domain_alloc(ec_domain_t *, uint32_t);
-
void ec_domain_queue_datagrams(ec_domain_t *);
-void ec_domain_dequeue_datagrams(ec_domain_t *);
/*****************************************************************************/
--- a/master/fsm.c Thu Oct 26 16:45:33 2006 +0000
+++ b/master/fsm.c Fri Oct 27 09:19:58 2006 +0000
@@ -226,7 +226,7 @@
if (topology_change && master->mode == EC_MASTER_MODE_IDLE) {
ec_master_eoe_stop(master);
- ec_master_clear_slaves(master);
+ ec_master_destroy_slaves(master);
master->slave_count = datagram->working_counter;
@@ -241,14 +241,14 @@
if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t),
GFP_ATOMIC))) {
EC_ERR("Failed to allocate slave %i!\n", i);
- ec_master_clear_slaves(master);
+ ec_master_destroy_slaves(master);
fsm->master_state = ec_fsm_master_error;
return;
}
if (ec_slave_init(slave, master, i, i + 1)) {
// freeing of "slave" already done
- ec_master_clear_slaves(master);
+ ec_master_destroy_slaves(master);
fsm->master_state = ec_fsm_master_error;
return;
}
@@ -256,7 +256,7 @@
if (kobject_add(&slave->kobj)) {
EC_ERR("Failed to add kobject.\n");
kobject_put(&slave->kobj); // free
- ec_master_clear_slaves(master);
+ ec_master_destroy_slaves(master);
fsm->master_state = ec_fsm_master_error;
return;
}
--- a/master/master.c Thu Oct 26 16:45:33 2006 +0000
+++ b/master/master.c Fri Oct 27 09:19:58 2006 +0000
@@ -55,6 +55,7 @@
/*****************************************************************************/
void ec_master_clear(struct kobject *);
+void ec_master_destroy_domains(ec_master_t *);
void ec_master_sync_io(ec_master_t *);
void ec_master_idle_run(void *);
void ec_master_eoe_run(unsigned long);
@@ -222,8 +223,25 @@
/**
Master destructor.
- Removes all pending datagrams, clears the slave list, clears all domains
- and frees the device.
+ Clears the kobj-hierarchy bottom up and frees the master.
+*/
+
+void ec_master_destroy(ec_master_t *master /**< EtherCAT master */)
+{
+ ec_master_destroy_slaves(master);
+ ec_master_destroy_domains(master);
+
+ // destroy self
+ kobject_del(&master->kobj);
+ kobject_put(&master->kobj); // free master
+}
+
+/*****************************************************************************/
+
+/**
+ Clear and free master.
+ This method is called by the kobject,
+ once there are no more references to it.
*/
void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
@@ -232,8 +250,6 @@
ec_eoe_t *eoe, *next_eoe;
ec_datagram_t *datagram, *next_c;
- ec_master_clear_slaves(master);
-
// empty datagram queue
list_for_each_entry_safe(datagram, next_c,
&master->datagram_queue, queue) {
@@ -252,7 +268,7 @@
kfree(eoe);
}
- EC_INFO("Master %i cleared.\n", master->index);
+ EC_INFO("Master %i freed.\n", master->index);
kfree(master);
}
@@ -260,17 +276,16 @@
/*****************************************************************************/
/**
- Clears all slaves.
-*/
-
-void ec_master_clear_slaves(ec_master_t *master)
+ Destroy all slaves.
+*/
+
+void ec_master_destroy_slaves(ec_master_t *master)
{
ec_slave_t *slave, *next_slave;
list_for_each_entry_safe(slave, next_slave, &master->slaves, list) {
list_del(&slave->list);
- kobject_del(&slave->kobj);
- kobject_put(&slave->kobj);
+ ec_slave_destroy(slave);
}
master->slave_count = 0;
@@ -279,6 +294,22 @@
/*****************************************************************************/
/**
+ Destroy all domains.
+*/
+
+void ec_master_destroy_domains(ec_master_t *master)
+{
+ ec_domain_t *domain, *next_d;
+
+ list_for_each_entry_safe(domain, next_d, &master->domains, list) {
+ list_del(&domain->list);
+ ec_domain_destroy(domain);
+ }
+}
+
+/*****************************************************************************/
+
+/**
Flushes the SDO request queue.
*/
@@ -386,15 +417,8 @@
/**< EtherCAT master */)
{
ec_slave_t *slave;
- ec_domain_t *domain, *next_d;
-
- // clear domains
- list_for_each_entry_safe(domain, next_d, &master->domains, list) {
- ec_domain_dequeue_datagrams(domain);
- list_del(&domain->list);
- kobject_del(&domain->kobj);
- kobject_put(&domain->kobj);
- }
+
+ ec_master_destroy_domains(master);
master->request_cb = NULL;
master->release_cb = NULL;
--- a/master/master.h Thu Oct 26 16:45:33 2006 +0000
+++ b/master/master.h Fri Oct 27 09:19:58 2006 +0000
@@ -148,8 +148,9 @@
/*****************************************************************************/
-// master creation
+// master creation/deletion
int ec_master_init(ec_master_t *, unsigned int, unsigned int, dev_t);
+void ec_master_destroy(ec_master_t *);
// mode transitions
int ec_master_enter_idle_mode(ec_master_t *);
@@ -167,7 +168,7 @@
// misc.
void ec_master_output_stats(ec_master_t *);
-void ec_master_clear_slaves(ec_master_t *);
+void ec_master_destroy_slaves(ec_master_t *);
void ec_master_calc_addressing(ec_master_t *);
// helper functions
--- a/master/module.c Thu Oct 26 16:45:33 2006 +0000
+++ b/master/module.c Fri Oct 27 09:19:58 2006 +0000
@@ -152,8 +152,7 @@
list_for_each_entry_safe(master, next, &ec_masters, list) {
list_del(&master->list);
- kobject_del(&master->kobj);
- kobject_put(&master->kobj); // free master
+ ec_master_destroy(master);
}
unregister_chrdev_region(device_number, ec_master_count);
--- a/master/slave.c Thu Oct 26 16:45:33 2006 +0000
+++ b/master/slave.c Fri Oct 27 09:19:58 2006 +0000
@@ -189,6 +189,34 @@
/**
Slave destructor.
+ Clears and frees a slave object.
+*/
+
+void ec_slave_destroy(ec_slave_t *slave /**< EtherCAT slave */)
+{
+ ec_sdo_t *sdo, *next_sdo;
+
+ // free all SDOs
+ list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) {
+ list_del(&sdo->list);
+ ec_sdo_destroy(sdo);
+ }
+
+ // free SDO kobject
+ if (slave->sdo_dictionary_fetched) kobject_del(&slave->sdo_kobj);
+ kobject_put(&slave->sdo_kobj);
+
+ // destroy self
+ kobject_del(&slave->kobj);
+ kobject_put(&slave->kobj);
+}
+
+/*****************************************************************************/
+
+/**
+ Clear and free slave.
+ This method is called by the kobject,
+ once there are no more references to it.
*/
void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
@@ -198,7 +226,6 @@
ec_sii_sync_t *sync, *next_sync;
ec_sii_pdo_t *pdo, *next_pdo;
ec_sii_pdo_entry_t *entry, *next_ent;
- ec_sdo_t *sdo, *next_sdo;
ec_sdo_data_t *sdodata, *next_sdodata;
slave = container_of(kobj, ec_slave_t, kobj);
@@ -235,17 +262,6 @@
if (slave->sii_order) kfree(slave->sii_order);
if (slave->sii_name) kfree(slave->sii_name);
- // free all SDOs
- list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) {
- list_del(&sdo->list);
- kobject_del(&sdo->kobj);
- kobject_put(&sdo->kobj);
- }
-
- // free SDO kobject FIXME
- if (slave->sdo_dictionary_fetched) kobject_del(&slave->sdo_kobj);
- kobject_put(&slave->sdo_kobj);
-
// free all SDO configurations
list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) {
list_del(&sdodata->list);
--- a/master/slave.h Thu Oct 26 16:45:33 2006 +0000
+++ b/master/slave.h Fri Oct 27 09:19:58 2006 +0000
@@ -259,6 +259,7 @@
// slave construction/destruction
int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t);
+void ec_slave_destroy(ec_slave_t *);
void ec_slave_reset(ec_slave_t *);