# HG changeset patch # User Florian Pose # Date 1168425957 0 # Node ID 8b20781bd1e07ddadeeecc8135d35a21d8aa15b0 # Parent 5ffcb9b9f17d29a5fe53761acc23f3ecbbb36d8f Master workqueue replaced with kernel thread. diff -r 5ffcb9b9f17d -r 8b20781bd1e0 master/master.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); } /*****************************************************************************/ diff -r 5ffcb9b9f17d -r 8b20781bd1e0 master/master.h --- 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 */ diff -r 5ffcb9b9f17d -r 8b20781bd1e0 master/module.c --- 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; }