Master workqueue replaced with kernel thread.
--- a/master/master.c Tue Jan 09 14:51:00 2007 +0000
+++ b/master/master.c Wed Jan 10 10:45:57 2007 +0000
@@ -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 @@
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 @@
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 @@
kfree(eoe);
}
ec_xmldev_clear(&master->xmldev);
- out_clear_wq:
- destroy_workqueue(master->workqueue);
out_return:
return -1;
}
@@ -263,7 +253,6 @@
}
ec_fsm_clear(&master->fsm);
- destroy_workqueue(master->workqueue);
ec_xmldev_clear(&master->xmldev);
// clear EoE objects
@@ -353,6 +342,38 @@
/*****************************************************************************/
/**
+ * 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");
+ }
+}
+
+/*****************************************************************************/
+
+/**
*/
int ec_master_enter_idle_mode(ec_master_t *master /**< EtherCAT master */)
@@ -362,7 +383,11 @@
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 @@
void ec_master_leave_idle_mode(ec_master_t *master /**< EtherCAT master */)
{
+ master->mode = EC_MASTER_MODE_ORPHANED;
+
ec_master_eoe_stop(master);
-
- master->mode = EC_MASTER_MODE_ORPHANED;
- while (!cancel_delayed_work(&master->idle_work)) {
- flush_workqueue(master->workqueue);
- }
-
+ ec_master_thread_stop(master);
ec_master_flush_sdo_requests(master);
}
@@ -395,11 +417,9 @@
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 @@
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 @@
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 @@
/*****************************************************************************/
/**
- Idle mode function.
-*/
-
-void ec_master_idle_run(void *data /**< master pointer */)
+ Master kernel thread function.
+*/
+
+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);
}
/*****************************************************************************/
--- a/master/master.h Tue Jan 09 14:51:00 2007 +0000
+++ b/master/master.h Wed Jan 10 10:45:57 2007 +0000
@@ -118,8 +118,8 @@
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 */
--- a/master/module.c Tue Jan 09 14:51:00 2007 +0000
+++ b/master/module.c Wed Jan 10 10:45:57 2007 +0000
@@ -372,7 +372,11 @@
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;
}