Master workqueue replaced with kernel thread.
authorFlorian Pose <fp@igh-essen.com>
Wed, 10 Jan 2007 10:45:57 +0000
changeset 525 8b20781bd1e0
parent 524 5ffcb9b9f17d
child 526 56522899acd1
Master workqueue replaced with kernel thread.
master/master.c
master/master.h
master/module.c
--- 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;
 }