Thread: [RTnet-developers] Joint Slots patch
Brought to you by:
bet-frogger,
kiszka
|
From: Vareka, B. <BV...@am...> - 2005-10-21 17:00:05
|
Here is a patch to add the option of joint slots. I have not had a chance to
fully test this but the changes are fairly confined so this should be good.
The basic idea is that you define multiple slots but all but the first are
defined as 'joined' to the first one. Then when you write via the socket,
the data goes to a common slot buffer and is sent in the next assigned slot.
This can be used to significantly reduce latencies without requiring very
short cycle periods.
The changes are:
1) add a -j option to tdmacfg for 'slots' which takes the joint slot id. It
will be required that the slot you want to reference to must have already
been defined before you define the joint slot. Also, the mtu's of both
the slot your joining and your own slot must be the same.
2) The tdma_config struct adds an additional int field called jointslot to
the set_slot union. A value between 0 and MaxSlots indicates a
desire to be coupled. Default is -1 (no coupling).
3) Modify the tdma_slot by changing the 'queue' member to be a pointer to a
rtskb_prio_queue and add an additional actual rtskb_prio_queue called
myqueue.
4) By default, slot->queue just points to &slot->myqueue.
5) The act of joining is achieved by changing slot->queue to point to
another pre-existing slot's myqueue member.
6) the rest of the tdma_slot structs for the two joint slots are not
identical because this is where things like offset, period and phasing info
are kept and those are different for the two slots. Only the
rtskb_prio_queue is common between them.
7) If you remove a slot which is jointed to another slot but you're not the
reference, then you just delete normally. But if others have queue pointer
pointing to your myqueue object then all those slots have their queue's
redirected to their own myqueue objects. Obviously, care is taken that this
is done when ref_count is 0 so we don't corrupt a loop in progress.
8) The only other impact is a few function calls which currently have
&slot->queue which needed to be changed to slot->queue since it's a pointer
already.
9) An unrelated bug was addressed, in the original tdma_ioctl.c file on line
474 the original code had
while ((rtskb = __rtskb_prio_dequeue(&slot->queue)))
but I believe the correct call should have been
while ((rtskb = __rtskb_prio_dequeue(&old_slot->queue)))
I've incorporated that into this patch as well but it is really independent
of the joint-slots changes.
Unlike what I stated in an earlier post, this no longer treats the NRT slot
any different from the others, thus you can also join to it if you want.
Regards,
Bill
********* patch ************************
diff -Naur rtnet-0.8.3/stack/include/rtmac/tdma/tdma.h
rtnet-0.8.3new/stack/include/rtmac/tdma/tdma.h
--- rtnet-0.8.3/stack/include/rtmac/tdma/tdma.h 2005-02-28
04:27:34.000000000 -0600
+++ rtnet-0.8.3new/stack/include/rtmac/tdma/tdma.h 2005-08-18
08:39:22.000000000 -0500
@@ -78,7 +78,8 @@
unsigned int phasing;
unsigned int mtu;
unsigned int size;
- struct rtskb_prio_queue queue;
+ struct rtskb_prio_queue *queue;
+ struct rtskb_prio_queue myqueue;
};
diff -Naur rtnet-0.8.3/stack/include/tdma_chrdev.h
rtnet-0.8.3new/stack/include/tdma_chrdev.h
--- rtnet-0.8.3/stack/include/tdma_chrdev.h 2004-11-17
02:09:44.000000000 -0600
+++ rtnet-0.8.3new/stack/include/tdma_chrdev.h 2005-08-18
08:40:02.000000000 -0500
@@ -54,6 +54,7 @@
unsigned int period;
unsigned int phasing;
unsigned int size;
+ int jointslot;
unsigned int cal_timeout;
__u64 *cal_results;
} set_slot;
diff -Naur rtnet-0.8.3/stack/rtmac/tdma/tdma_ioctl.c
rtnet-0.8.3new/stack/rtmac/tdma/tdma_ioctl.c
--- rtnet-0.8.3/stack/rtmac/tdma/tdma_ioctl.c 2005-02-28
04:27:34.000000000 -0600
+++ rtnet-0.8.3new/stack/rtmac/tdma/tdma_ioctl.c 2005-08-18
02:54:34.000000000 -0500
@@ -299,7 +299,7 @@
struct rtskb *rtskb;
unsigned int job_list_revision;
unsigned long flags;
- int ret;
+ int ret, ii, jntId;
if (rtdev->mac_priv == NULL)
@@ -318,6 +318,15 @@
else if (cfg->args.set_slot.size > rtdev->mtu)
return -EINVAL;
+ jntId = cfg->args.set_slot.jointslot;
+ if( (jntId >=0 ) &&
+ ( (jntId >= tdma->max_slot_id)
+ || (tdma->slot_table[jntId] == 0)
+ || (tdma->slot_table[jntId]->mtu != cfg->args.set_slot.size)
+ ) )
+ return -EINVAL;
+
+
slot = (struct tdma_slot *)kmalloc(sizeof(struct tdma_slot),
GFP_KERNEL);
if (!slot)
return -ENOMEM;
@@ -402,8 +411,12 @@
slot->phasing = cfg->args.set_slot.phasing;
slot->mtu = cfg->args.set_slot.size;
slot->size = cfg->args.set_slot.size +
rtdev->hard_header_len;
+ slot->queue = &slot->myqueue;
rtos_nanosecs_to_time(cfg->args.set_slot.offset, &slot->offset);
- rtskb_prio_queue_init(&slot->queue);
+ rtskb_prio_queue_init(slot->queue);
+
+ if(jntId >=0 ) //all other validation tests performed above.
+ slot->queue = tdma->slot_table[jntId]->queue;
old_slot = tdma->slot_table[id];
if ((id == DEFAULT_NRT_SLOT) &&
@@ -454,13 +467,27 @@
(tdma->slot_table[DEFAULT_NRT_SLOT] == old_slot))
tdma->slot_table[DEFAULT_NRT_SLOT] = slot;
- if (old_slot)
+ if (old_slot) {
while (old_slot->head.ref_count > 0) {
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/10); /* wait 100 ms */
rtos_spin_lock_irqsave(&tdma->lock, flags);
}
+ //if others were linked to my prio que, move them to the new one.
+ for(ii=0; ii<tdma->max_slot_id; ii++) {
+ if( (tdma->slot_table[ii] != 0)
+ && (tdma->slot_table[ii]->queue == &old_slot->myqueue)) {
+ while (tdma->slot_table[ii]->head.ref_count > 0) {
+ rtos_spin_unlock_irqrestore(&tdma->lock, flags);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10); /* wait 100 ms */
+ rtos_spin_lock_irqsave(&tdma->lock, flags);
+ } //end while, safe to change queue pointer
+ tdma->slot_table[ii]->queue = slot->queue;
+ }
+ }
+ }
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
@@ -471,7 +498,8 @@
without lock protection.
NOTE: Reconfiguring a slot during runtime may lead to packet
drops! */
- while ((rtskb = __rtskb_prio_dequeue(&slot->queue)))
+ old_slot->queue = &old_slot->myqueue;
+ while ((rtskb = __rtskb_prio_dequeue(old_slot->queue)))
kfree_rtskb(rtskb);
kfree(old_slot);
@@ -501,10 +529,24 @@
if (id == DEFAULT_NRT_SLOT)
tdma->slot_table[DEFAULT_NRT_SLOT] =
tdma->slot_table[DEFAULT_SLOT];
else {
+ int ii;
if ((id == DEFAULT_SLOT) &&
(tdma->slot_table[DEFAULT_NRT_SLOT] == slot))
tdma->slot_table[DEFAULT_NRT_SLOT] = NULL;
tdma->slot_table[id] = NULL;
+ //search for other slots linked to my queue and detach them
+ for(ii=0; ii<tdma->max_slot_id; ii++) {
+ if( (tdma->slot_table[ii] != 0) &&
+ (tdma->slot_table[ii]->queue == &slot->myqueue)) {
+ while (tdma->slot_table[ii]->head.ref_count > 0) {
+ rtos_spin_unlock_irqrestore(&tdma->lock, flags);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10); /* wait 100 ms */
+ rtos_spin_lock_irqsave(&tdma->lock, flags);
+ } //end while, safe to move queue pointer
+ tdma->slot_table[ii]->queue =
&tdma->slot_table[ii]->myqueue;
+ }
+ }
}
while (slot->head.ref_count > 0) {
@@ -518,7 +560,8 @@
/* No need to protect the queue access here -
no one is referring to this job anymore (ref_count == 0). */
- while ((rtskb = __rtskb_prio_dequeue(&slot->queue)))
+ slot->queue = &slot->myqueue;
+ while ((rtskb = __rtskb_prio_dequeue(slot->queue)))
kfree_rtskb(rtskb);
kfree(slot);
diff -Naur rtnet-0.8.3/stack/rtmac/tdma/tdma_proto.c
rtnet-0.8.3new/stack/rtmac/tdma/tdma_proto.c
--- rtnet-0.8.3/stack/rtmac/tdma/tdma_proto.c 2005-02-28
04:27:34.000000000 -0600
+++ rtnet-0.8.3new/stack/rtmac/tdma/tdma_proto.c 2005-08-18
09:00:04.000000000 -0500
@@ -155,7 +155,7 @@
goto err_out;
}
- __rtskb_prio_queue_tail(&slot->queue, rtskb);
+ __rtskb_prio_queue_tail(slot->queue, rtskb);
err_out:
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
@@ -193,7 +193,7 @@
goto err_out;
}
- __rtskb_prio_queue_tail(&slot->queue, rtskb);
+ __rtskb_prio_queue_tail(slot->queue, rtskb);
err_out:
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
diff -Naur rtnet-0.8.3/stack/rtmac/tdma/tdma_worker.c
rtnet-0.8.3new/stack/rtmac/tdma/tdma_worker.c
--- rtnet-0.8.3/stack/rtmac/tdma/tdma_worker.c 2004-12-06
02:10:44.000000000 -0600
+++ rtnet-0.8.3new/stack/rtmac/tdma/tdma_worker.c 2005-08-18
09:00:48.000000000 -0500
@@ -58,7 +58,7 @@
rtos_task_sleep_until(&time);
rtos_spin_lock_irqsave(&tdma->lock, flags);
- rtskb = __rtskb_prio_dequeue(&SLOT_JOB(job)->queue);
+ rtskb = __rtskb_prio_dequeue(SLOT_JOB(job)->queue);
if (!rtskb)
goto continue_in_lock;
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
diff -Naur rtnet-0.8.3/tools/tdmacfg.c rtnet-0.8.3new/tools/tdmacfg.c
--- rtnet-0.8.3/tools/tdmacfg.c 2004-12-02 03:39:38.000000000 -0600
+++ rtnet-0.8.3new/tools/tdmacfg.c 2005-08-18 09:05:38.000000000 -0500
@@ -44,7 +44,7 @@
"\t [-m max_calibration_requests]\n"
"\ttdmacfg <dev> slave [-c calibration_rounds] [-i max_slot_id]\n"
"\ttdmacfg <dev> slot <id> [<offset> [-p <phasing>/<period>] "
- "[-s <size>]\n"
+ "[-s <size>] [-j <joint_slot_id>]\n"
"\t [-l calibration_log_file] [-t calibration_timeout]]\n"
"\ttdmacfg <dev> detach\n");
@@ -60,7 +60,7 @@
if (pos >= argc)
help();
- if ((sscanf(argv[pos], "%u", &result) != 1) || (result < min)) {
+ if ((sscanf(argv[pos], "%i", &result) != 1) || (result < min)) {
fprintf(stderr, "invalid parameter: %s %s\n", argv[pos-1],
argv[pos]);
exit(1);
}
@@ -208,6 +208,7 @@
tdma_cfg.args.set_slot.phasing = 0;
tdma_cfg.args.set_slot.size = 0;
tdma_cfg.args.set_slot.cal_timeout = 0;
+ tdma_cfg.args.set_slot.jointslot = -1;
tdma_cfg.args.set_slot.cal_results = NULL;
for (i = 5; i < argc; i++) {
@@ -236,6 +237,9 @@
else if (strcmp(argv[i], "-t") == 0)
tdma_cfg.args.set_slot.cal_timeout =
getintopt(argc, ++i, argv, 0);
+ else if (strcmp(argv[i], "-j") == 0)
+ tdma_cfg.args.set_slot.jointslot =
+ getintopt(argc, ++i, argv, -1);
else
help();
}
|
|
From: Jan K. <ki...@rt...> - 2005-10-21 18:57:20
Attachments:
signature.asc
|
Vareka, Bill wrote: > Here is a patch to add the option of joint slots. I have not had a chance to > fully test this but the changes are fairly confined so this should be good. > Great work, and also very well described. Thanks for your contribution! > The basic idea is that you define multiple slots but all but the first are > defined as 'joined' to the first one. Then when you write via the socket, > the data goes to a common slot buffer and is sent in the next assigned slot. > This can be used to significantly reduce latencies without requiring very > short cycle periods. > > The changes are: > 1) add a -j option to tdmacfg for 'slots' which takes the joint slot id. It > will be required that the slot you want to reference to must have already > been defined before you define the joint slot. Also, the mtu's of both > the slot your joining and your own slot must be the same. > > 2) The tdma_config struct adds an additional int field called jointslot to > the set_slot union. A value between 0 and MaxSlots indicates a > desire to be coupled. Default is -1 (no coupling). > > 3) Modify the tdma_slot by changing the 'queue' member to be a pointer to a > rtskb_prio_queue and add an additional actual rtskb_prio_queue called > myqueue. > > 4) By default, slot->queue just points to &slot->myqueue. > > 5) The act of joining is achieved by changing slot->queue to point to > another pre-existing slot's myqueue member. > > 6) the rest of the tdma_slot structs for the two joint slots are not > identical because this is where things like offset, period and phasing info > are kept and those are different for the two slots. Only the > rtskb_prio_queue is common between them. > > 7) If you remove a slot which is jointed to another slot but you're not the > reference, then you just delete normally. But if others have queue pointer > pointing to your myqueue object then all those slots have their queue's > redirected to their own myqueue objects. Obviously, care is taken that this > is done when ref_count is 0 so we don't corrupt a loop in progress. > > 8) The only other impact is a few function calls which currently have > &slot->queue which needed to be changed to slot->queue since it's a pointer > already. Looks good. On the first glace I had some concerns regarding the loops over all slots under spinlock to find potential mates (even when there are none), but I see no other simple solution so far. Will try to think about it further, though. > > 9) An unrelated bug was addressed, in the original tdma_ioctl.c file on line > 474 the original code had > while ((rtskb = __rtskb_prio_dequeue(&slot->queue))) > but I believe the correct call should have been > while ((rtskb = __rtskb_prio_dequeue(&old_slot->queue))) > I've incorporated that into this patch as well but it is really independent > of the joint-slots changes. Oh, yes, good spot. Looks like some real cleanup bug... > > Unlike what I stated in an earlier post, this no longer treats the NRT slot > any different from the others, thus you can also join to it if you want. > Ok, I have some code refactoring still pending on my box which I would like to finish and check in first, but then it will be your patch's turn. Should definitely make it into SVN for the next release! Jan |
|
From: Jan K. <ki...@rt...> - 2005-10-23 19:03:25
Attachments:
signature.asc
|
Vareka, Bill wrote: > Here is a patch to add the option of joint slots. I have not had a chance to > fully test this but the changes are fairly confined so this should be good. > ... Ok, your patch with some modifications and extensions is in the SVN. Compiles and /seems/ to run well on top of Xenomai 2.0. It only "seems" to work as I'm currently too busy to set up a second box, so I only checked if outgoing packets to nowhere are being scattered across the new joint slots - they are. 8) What I did differently: I broke up the lock when traversing the slot list on cleanup and reconfigure for potential joint slots. I also applied a stricter check when the head of a slot chain gets changed (smaller MTU permissible, larger will break up the chain). Moreover, I added /proc support so that you can see what you configured. ;) More tests certainly required. I hope to spent some time on this the next days and then roll out a release candidate for 0.9.0. Thanks again for your work, Jan |