+
+void virtual_schedule_next(struct msgobj_t *obj)
+{
+ int cmd;
+ /* dummy lock to prevent preemption fully portable way */
+ spinlock_t dummy_lock;
+
+ /* preempt_disable() */
+ spin_lock_init(&dummy_lock);
+ spin_lock(&dummy_lock);
+
+ set_bit(OBJ_TX_REQUEST,&obj->flags);
+
+ while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
+
+ clear_bit(OBJ_TX_REQUEST,&obj->flags);
+
+ cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
+ if(cmd>=0) {
+ mod_timer(&obj->tx_timeout,
+ jiffies+virtual_bus_latency(obj));
+ CANMSG("virtual: scheduled delivery\n");
+
+ } else
+ clear_bit(OBJ_TX_LOCK,&obj->flags);
+
+ if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ DEBUGMSG("TX looping in virtual_schedule_next\n");
+ }
+
+ /* preempt_enable(); */
+ spin_unlock(&dummy_lock);
+}
+
+
+void virtual_do_tx_timeout(unsigned long data)
+{
+ struct msgobj_t *obj=(struct msgobj_t *)data;
+
+ if(obj->tx_slot) {
+ /* Deliver message to edges */
+ canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+ /* Free transmitted slot */
+ canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+ obj->tx_slot=NULL;
+ CANMSG("virtual: delayed delivery\n");
+ }
+ clear_bit(OBJ_TX_LOCK,&obj->flags);
+
+ virtual_schedule_next(obj);
+}
+