<div dir="ltr">Yes, it makes perfect sense.<div><br></div><div>Thank you for the clarification.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jul 24, 2020 at 11:29 PM Gedare Bloom <<a href="mailto:gedare@rtems.org">gedare@rtems.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Fri, Jul 24, 2020 at 8:27 AM Richi Dubey <<a href="mailto:richidubey@gmail.com" target="_blank">richidubey@gmail.com</a>> wrote:<br>
><br>
> Hi,<br>
><br>
> I have a doubt regarding this.<br>
><br>
> We do<br>
>   rtems_chain_append( &chain1, &node1.Node );<br>
><br>
> And get the node pointer when we use:<br>
>   rtems_chain_node    *p= rtems_chain_first(&chain1),<br>
><br>
> After this, Do we really need to use the CONTAINER_OF and other such methods?<br>
><br>
> Can we not simply do:<br>
>   test_node node1=(test_node*) p;<br>
><br>
><br>
> Since our structure test_node has the  rtems_chain_node Node; as its first variable, it should work, right?<br>
><br>
<br>
If the Node is the first variable, then it just works without<br>
container-of. But then you need to make sure no one will change the<br>
structure definition (at least, make a comment about it).<br>
<br>
The RTEMS Object model makes use of this simplification. The base<br>
'Object' includes a chain Node at the start of the struct, so that<br>
when you include an Object at the start of a struct, you automatically<br>
get a Node at the base address of an instantiated struct.<br>
<br>
The downsides of this assumption are that you have to make the struct<br>
layout rigid (as mentioned), and you also can't reuse the same code<br>
base with nodes belonging to multiple data structures, e.g., you can't<br>
put a single struct on two chains, if both chains assume they get the<br>
base address of the struct, since only one Node can possibly be at the<br>
base of the structure.<br>
<br>
I hope that makes sense.<br>
<br>
> References:<br>
> <a href="https://stackoverflow.com/q/3766229" rel="noreferrer" target="_blank">https://stackoverflow.com/q/3766229</a><br>
> <a href="https://git.rtems.org/rtems/tree/cpukit/score/src/scheduleredfsmp.c#n178" rel="noreferrer" target="_blank">https://git.rtems.org/rtems/tree/cpukit/score/src/scheduleredfsmp.c#n178</a><br>
><br>
> Please let me know.<br>
> Thanks.<br>
><br>
> On Fri, Jun 12, 2020 at 7:28 PM Gedare Bloom <<a href="mailto:gedare@rtems.org" target="_blank">gedare@rtems.org</a>> wrote:<br>
>><br>
>> On Fri, Jun 12, 2020 at 7:50 AM Richi Dubey <<a href="mailto:richidubey@gmail.com" target="_blank">richidubey@gmail.com</a>> wrote:<br>
>> ><br>
>> > Hi everyone,<br>
>> ><br>
>> > While going through testsuites/sptests/spchain/init.c, I noticed the following code:<br>
>> ><br>
>> > -----------------------------------------------<br>
>> > rtems_task Init(<br>
>> >   rtems_task_argument ignored<br>
>> > )<br>
>> > {<br>
>> >   rtems_chain_control  chain1;<br>
>> >   rtems_chain_node    *p;<br>
>> >   test_node            node1, node2;<br>
>> >   int                  id;<br>
>> ><br>
>> >   TEST_BEGIN();<br>
>> ><br>
>> >   puts( "Init - Initialize chain empty" );<br>
>> >   rtems_chain_initialize_empty( &chain1 );<br>
>> >   rtems_chain_initialize_node( &node1.Node );<br>
>> >   rtems_chain_initialize_node( &node2.Node );<br>
>> ><br>
>> >   /* verify that the chain append and insert work */<br>
>> >   puts( "INIT - Verify rtems_chain_insert" );<br>
>> >   <a href="http://node1.id" rel="noreferrer" target="_blank">node1.id</a> = 1;<br>
>> >   <a href="http://node2.id" rel="noreferrer" target="_blank">node2.id</a> = 2;<br>
>> >   rtems_chain_append( &chain1, &node1.Node );<br>
>> >   rtems_chain_insert( &node1.Node, &node2.Node );<br>
>> ><br>
>> >   for ( p = rtems_chain_first(&chain1), id = 1 ;<br>
>> >         !rtems_chain_is_tail(&chain1, p) ;<br>
>> >         p = p->next , id++ ) {<br>
>> >      test_node *t = (test_node *)p;<br>
>> >      if ( id > 2 ) {<br>
>> >        puts( "INIT - TOO MANY NODES ON CHAIN" );<br>
>> >        rtems_test_exit(0);<br>
>> >      }<br>
>> >      if ( t->id != id ) {<br>
>> >        puts( "INIT - ERROR ON CHAIN ID MISMATCH" );<br>
>> >        rtems_test_exit(0);<br>
>> >      }<br>
>> >   }<br>
>> ><br>
>> > -----------------------------------------<br>
>> > Where test_node is defined as:<br>
>> ><br>
>> > typedef struct {<br>
>> >   rtems_chain_node Node;<br>
>> >   int              id;<br>
>> > } test_node;<br>
>> ><br>
>> > ----------------------------------<br>
>> ><br>
>> ><br>
>> > Now when we are inserting or appending our structure into the chain, we are only inserting the part of strucuture correspoing to rtems_chain_node, i.e.:<br>
>> >   rtems_chain_append( &chain1, &node1.Node );<br>
>> >   rtems_chain_insert( &node1.Node, &node2.Node );<br>
>> ><br>
>> > So, how do we ever get our <a href="http://node1.id" rel="noreferrer" target="_blank">node1.id</a> ? How can we (or how do we ever) access our data from the structure when we are only adding some part of the structure into the node?<br>
>> ><br>
>> > I hope my doubt is not too vague.<br>
>> ><br>
>> Hi Richi,<br>
>><br>
>> This is an old C programming trick.<br>
>><br>
>> This looks like a reasonable explanation:<br>
>> <a href="https://medium.com/@414apache/kernel-data-structures-linkedlist-b13e4f8de4bf" rel="noreferrer" target="_blank">https://medium.com/@414apache/kernel-data-structures-linkedlist-b13e4f8de4bf</a><br>
>><br>
>> Feel free to write something for rtems ;)<br>
>><br>
>> > Thanks,<br>
>> > Richi.<br>
>> ><br>
>> ><br>
>> > _______________________________________________<br>
>> > devel mailing list<br>
>> > <a href="mailto:devel@rtems.org" target="_blank">devel@rtems.org</a><br>
>> > <a href="http://lists.rtems.org/mailman/listinfo/devel" rel="noreferrer" target="_blank">http://lists.rtems.org/mailman/listinfo/devel</a><br>
</blockquote></div>