Master workqueue replaced with kernel thread.

This commit is contained in:
Florian Pose 2007-01-10 10:45:57 +00:00
parent 81acf0c368
commit ea7e0ca982
3 changed files with 89 additions and 54 deletions

View File

@ -57,7 +57,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 *);
static int ec_master_thread(void *);
void ec_master_eoe_run(unsigned long);
void ec_master_check_sdo(unsigned long);
int ec_master_measure_bus_time(ec_master_t *);
@ -134,8 +134,6 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
master->stats.unmatched = 0;
master->stats.output_jiffies = 0;
INIT_WORK(&master->idle_work, ec_master_idle_run, (void *) master);
for (i = 0; i < HZ; i++) {
master->idle_cycle_times[i] = 0;
master->eoe_cycle_times[i] = 0;
@ -166,16 +164,10 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
master->sdo_timer.data = (unsigned long) master;
init_completion(&master->sdo_complete);
// create workqueue
if (!(master->workqueue = create_singlethread_workqueue("EtherCAT"))) {
EC_ERR("Failed to create master workqueue.\n");
goto out_return;
}
// init XML character device
if (ec_xmldev_init(&master->xmldev, master, dev_num)) {
EC_ERR("Failed to init XML character device.\n");
goto out_clear_wq;
goto out_return;
}
// create EoE handlers
@ -218,8 +210,6 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
kfree(eoe);
}
ec_xmldev_clear(&master->xmldev);
out_clear_wq:
destroy_workqueue(master->workqueue);
out_return:
return -1;
}
@ -263,7 +253,6 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
}
ec_fsm_clear(&master->fsm);
destroy_workqueue(master->workqueue);
ec_xmldev_clear(&master->xmldev);
// clear EoE objects
@ -352,6 +341,38 @@ void ec_master_release_cb(void *master /**< callback data */)
/*****************************************************************************/
/**
* Starts the master thread.
*/
int ec_master_thread_start(ec_master_t *master /**< EtherCAT master */)
{
init_completion(&master->thread_exit);
if (!(master->thread_id =
kernel_thread(ec_master_thread, master, CLONE_KERNEL)))
return -1;
return 0;
}
/*****************************************************************************/
/**
* Stops the master thread.
*/
void ec_master_thread_stop(ec_master_t *master /**< EtherCAT master */)
{
if (master->thread_id) {
kill_proc(master->thread_id, SIGTERM, 1);
wait_for_completion(&master->thread_exit);
EC_DBG("Master thread exited.\n");
}
}
/*****************************************************************************/
/**
*/
@ -362,7 +383,11 @@ int ec_master_enter_idle_mode(ec_master_t *master /**< EtherCAT master */)
master->cb_data = master;
master->mode = EC_MASTER_MODE_IDLE;
queue_delayed_work(master->workqueue, &master->idle_work, 1);
if (ec_master_thread_start(master)) {
master->mode = EC_MASTER_MODE_ORPHANED;
return -1;
}
return 0;
}
@ -373,13 +398,10 @@ int ec_master_enter_idle_mode(ec_master_t *master /**< EtherCAT master */)
void ec_master_leave_idle_mode(ec_master_t *master /**< EtherCAT master */)
{
ec_master_eoe_stop(master);
master->mode = EC_MASTER_MODE_ORPHANED;
while (!cancel_delayed_work(&master->idle_work)) {
flush_workqueue(master->workqueue);
}
ec_master_eoe_stop(master);
ec_master_thread_stop(master);
ec_master_flush_sdo_requests(master);
}
@ -395,11 +417,9 @@ int ec_master_enter_operation_mode(ec_master_t *master /**< EtherCAT master */)
ec_master_eoe_stop(master); // stop EoE timer
master->eoe_checked = 1; // prevent from starting again by FSM
ec_master_thread_stop(master);
master->mode = EC_MASTER_MODE_OPERATION;
while (!cancel_delayed_work(&master->idle_work)) {
flush_workqueue(master->workqueue);
}
// wait for FSM datagram
if (datagram->state == EC_DATAGRAM_SENT) {
@ -438,7 +458,9 @@ int ec_master_enter_operation_mode(ec_master_t *master /**< EtherCAT master */)
out_idle:
master->mode = EC_MASTER_MODE_IDLE;
queue_delayed_work(master->workqueue, &master->idle_work, 1);
if (ec_master_thread_start(master)) {
EC_WARN("Failed to start master thread again!\n");
}
return -1;
}
@ -497,7 +519,9 @@ void ec_master_leave_operation_mode(ec_master_t *master
master->eoe_checked = 0; // allow EoE again
master->mode = EC_MASTER_MODE_IDLE;
queue_delayed_work(master->workqueue, &master->idle_work, 1);
if (ec_master_thread_start(master)) {
EC_WARN("Failed to start master thread!\n");
}
}
/*****************************************************************************/
@ -768,39 +792,46 @@ void ec_master_output_stats(ec_master_t *master /**< EtherCAT master */)
/*****************************************************************************/
/**
Idle mode function.
Master kernel thread function.
*/
void ec_master_idle_run(void *data /**< master pointer */)
static int ec_master_thread(void *data)
{
ec_master_t *master = (ec_master_t *) data;
cycles_t cycles_start, cycles_end;
if (master->mode != EC_MASTER_MODE_IDLE) return;
daemonize("EtherCAT2");
allow_signal(SIGTERM);
while (!signal_pending(current) && master->mode == EC_MASTER_MODE_IDLE) {
cycles_start = get_cycles();
// receive
spin_lock_bh(&master->internal_lock);
ecrt_master_receive(master);
spin_unlock_bh(&master->internal_lock);
// execute master state machine
ec_fsm_exec(&master->fsm);
// send
spin_lock_bh(&master->internal_lock);
ecrt_master_send(master);
spin_unlock_bh(&master->internal_lock);
cycles_end = get_cycles();
master->idle_cycle_times[master->idle_cycle_time_pos]
= (u32) (cycles_end - cycles_start) * 1000 / cpu_khz;
master->idle_cycle_time_pos++;
master->idle_cycle_time_pos %= HZ;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
cycles_start = get_cycles();
// receive
spin_lock_bh(&master->internal_lock);
ecrt_master_receive(master);
spin_unlock_bh(&master->internal_lock);
// execute master state machine
ec_fsm_exec(&master->fsm);
// send
spin_lock_bh(&master->internal_lock);
ecrt_master_send(master);
spin_unlock_bh(&master->internal_lock);
cycles_end = get_cycles();
master->idle_cycle_times[master->idle_cycle_time_pos]
= (u32) (cycles_end - cycles_start) * 1000 / cpu_khz;
master->idle_cycle_time_pos++;
master->idle_cycle_time_pos %= HZ;
if (master->mode == EC_MASTER_MODE_IDLE)
queue_delayed_work(master->workqueue, &master->idle_work, 1);
EC_INFO("Master thread exiting.\n");
master->thread_id = 0;
complete_and_exit(&master->thread_exit, 0);
}
/*****************************************************************************/

View File

@ -118,8 +118,8 @@ struct ec_master
int debug_level; /**< master debug level */
ec_stats_t stats; /**< cyclic statistics */
struct workqueue_struct *workqueue; /**< master workqueue */
struct work_struct idle_work; /**< free run work object */
int thread_id; /**< master thread PID */
struct completion thread_exit; /**< thread completion object */
uint32_t idle_cycle_times[HZ]; /**< Idle cycle times ring */
unsigned int idle_cycle_time_pos; /**< time ring buffer position */

View File

@ -372,7 +372,11 @@ int ecdev_open(ec_device_t *device /**< EtherCAT device */)
return -1;
}
ec_master_enter_idle_mode(device->master);
if (ec_master_enter_idle_mode(device->master)) {
EC_ERR("Failed to enter idle mode!\n");
return -1;
}
return 0;
}