FIX: Introduced destroy() functions for kobject-derived classes and thus fixed memory leak.
This commit is contained in:
parent
bb8c90bcf9
commit
131589f534
|
|
@ -132,20 +132,36 @@ int ec_sdo_init(ec_sdo_t *sdo, /**< SDO */
|
|||
|
||||
/**
|
||||
SDO destructor.
|
||||
Clears and frees an SDO object.
|
||||
*/
|
||||
|
||||
void ec_sdo_clear(struct kobject *kobj /**< SDO's kobject */)
|
||||
void ec_sdo_destroy(ec_sdo_t *sdo /**< SDO */)
|
||||
{
|
||||
ec_sdo_t *sdo = container_of(kobj, ec_sdo_t, kobj);
|
||||
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);
|
||||
|
||||
kfree(sdo);
|
||||
|
|
@ -215,7 +231,23 @@ int ec_sdo_entry_init(ec_sdo_entry_t *entry, /**< SDO entry */
|
|||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
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 */)
|
||||
|
|
|
|||
|
|
@ -120,7 +120,10 @@ ec_sdo_request_t;
|
|||
/*****************************************************************************/
|
||||
|
||||
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 *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -130,6 +130,30 @@ int ec_domain_init(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
|
||||
/**
|
||||
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 */)
|
||||
|
|
@ -463,22 +487,6 @@ void ec_domain_queue_datagrams(ec_domain_t *domain /**< EtherCAT domain */)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
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
|
||||
|
|
|
|||
|
|
@ -76,11 +76,10 @@ struct ec_domain
|
|||
/*****************************************************************************/
|
||||
|
||||
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 *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
|
|||
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 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
|
|||
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 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
/**
|
||||
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 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
|
|||
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 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
|
|||
kfree(eoe);
|
||||
}
|
||||
|
||||
EC_INFO("Master %i cleared.\n", master->index);
|
||||
EC_INFO("Master %i freed.\n", master->index);
|
||||
|
||||
kfree(master);
|
||||
}
|
||||
|
|
@ -260,17 +276,16 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
|
|||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Clears all slaves.
|
||||
Destroy all slaves.
|
||||
*/
|
||||
|
||||
void ec_master_clear_slaves(ec_master_t *master)
|
||||
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;
|
||||
|
|
@ -278,6 +293,22 @@ void ec_master_clear_slaves(ec_master_t *master)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
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 @@ void ec_master_leave_operation_mode(ec_master_t *master
|
|||
/**< 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;
|
||||
|
|
|
|||
|
|
@ -148,8 +148,9 @@ struct ec_master
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
// 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 @@ void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
|
|||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -152,8 +152,7 @@ void __exit ec_cleanup_module(void)
|
|||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -189,6 +189,34 @@ int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */
|
|||
|
||||
/**
|
||||
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 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
|
|||
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 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ struct ec_slave
|
|||
|
||||
// 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 *);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue