> -----Original Message----- > From: EXT Maxim Uvarov [mailto:maxim.uva...@linaro.org] > Sent: Friday, September 11, 2015 12:47 PM > To: Savolainen, Petri (Nokia - FI/Espoo); EXT Bill Fischofer > Cc: LNG ODP Mailman List > Subject: Re: [lng-odp] [API-NEXT PATCH] api: packet reference count > support > > On 09/11/15 12:32, Savolainen, Petri (Nokia - FI/Espoo) wrote: > > > >> -----Original Message----- > >> From: EXT Maxim Uvarov [mailto:maxim.uva...@linaro.org] > >> Sent: Friday, September 11, 2015 11:30 AM > >> To: Savolainen, Petri (Nokia - FI/Espoo); EXT Bill Fischofer > >> Cc: LNG ODP Mailman List > >> Subject: Re: [lng-odp] [API-NEXT PATCH] api: packet reference count > >> support > >> > >> On 09/11/15 10:48, Savolainen, Petri (Nokia - FI/Espoo) wrote: > >>>> -----Original Message----- > >>>> From: EXT Maxim Uvarov [mailto:maxim.uva...@linaro.org] > >>>> Sent: Thursday, September 10, 2015 7:11 PM > >>>> To: Savolainen, Petri (Nokia - FI/Espoo); EXT Bill Fischofer > >>>> Cc: LNG ODP Mailman List > >>>> Subject: Re: [lng-odp] [API-NEXT PATCH] api: packet reference > count > >>>> support > >>>> > >>>> On 09/10/15 15:54, Savolainen, Petri (Nokia - FI/Espoo) wrote: > >>>>>> -----Original Message----- > >>>>>> From: EXT Maxim Uvarov [mailto:maxim.uva...@linaro.org] > >>>>>> Sent: Thursday, September 10, 2015 2:20 PM > >>>>>> To: Savolainen, Petri (Nokia - FI/Espoo); EXT Bill Fischofer > >>>>>> Cc: LNG ODP Mailman List > >>>>>> Subject: Re: [lng-odp] [API-NEXT PATCH] api: packet reference > >> count > >>>>>> support > >>>>>> > >>>>>> On 09/10/15 12:00, Savolainen, Petri (Nokia - FI/Espoo) wrote: > >>>>>>> The problem to solve is: how to enable multiple references to a > >>>>>> packet > >>>>>>> and more generally to a packet segment. It would be better to > >>>> create > >>>>>>> new handles, instead of increment a 32bit count. Currently, the > >>>>>>> ownership of a handle is lost during enq/free/… operations. > That > >>>>>>> semantic is worth maintaining also with multiple references. > >>>>>>> > >>>>>>> odp_packet_t pkt = current_packet; > >>>>>>> > >>>>>>> odp_packet_t my_ref; > >>>>>>> > >>>>>>> // Create new reference to a packet > >>>>>>> > >>>>>>> my_ref = odp_packet_create_ref(pkt); > >>>>>>> > >>>>>>> if (odp_packet_ref_count(pkt) > 1) > >>>>>>> > >>>>>>> // reference count is now 2 > >>>>>>> > >>>>>>> foo(); > >>>>>>> > >>>>>>> odp_packet_free(pkt); > >>>>>>> > >>>>>>> // After free, user does not own handle ‘pkt’ anymore and > cannot > >>>> it. > >>>>>>> if (odp_packet_ref_count(my_ref) > 1) > >>>>>>> > >>>>>>> // reference count is now 1 > >>>>>>> > >>>>>>> foo(); > >>>>>>> > >>>>>>> odp_packet_free(my_ref); > >>>>>>> > >>>>>>> // Packet is now freed and user does not have any reference to > it > >>>>>> anymore. > >>>>>> I think that uses case is not close to real life. If you do in > one > >>>>>> thread: > >>>>>> pkt = <get packet or alloc>; > >>>>>> odp_packet_refcount_set(pkt, 2); > >>>>>> foo(pkt); > >>>>>> odp_packet_free(pkt); <- ref is 1 > >>>>>> foo(pkt); > >>>>>> odp_packet_free(pkt); <- ref 0, free > >>>>>> > >>>>>> Then you know what pkt is on each line. Instead of having 2 > >>>> reference > >>>>>> as > >>>>>> in your example my_ref and pkt, you > >>>>>> use just one pkt. > >>>>> The point of the example is clear ownership of a reference to the > >>>> packet. > >>>>> These are *bugs* currently, and API should stay clear on > ownership > >>>> issues also multiple references: > >>>>> // double free a packet (handle or reference) > >>>>> odp_packet_free(pkt); > >>>>> odp_packet_free(pkt); > >>>>> > >>>>> > >>>>> // double enqueue a packet (handle or reference) > >>>>> ev = odp_packet_from_event(pkt); > >>>>> odp_queue_enq(queue1, ev); > >>>>> odp_queue_enq(queue2, ev); > >>>>> > >>>>> > >>>>> With two different handles (references) it's clear how owns the > >>>> handle and implementation can either return the same or different > >> value > >>>> as the handle. > >>>>> my_ref = odp_packet_create_ref(pkt); > >>>>> > >>>>> ev1 = odp_packet_from_event(pkt); > >>>>> odp_queue_enq(queue1, ev1); > >>>>> > >>>>> ev2 = odp_packet_from_event(my_ref); > >>>>> odp_queue_enq(queue2, ev2); > >>>>> > >>>> In my case it's easy to check, inside odp_packet_free(pkt): > >>>> if (!odp_packet_refcount(pkt)) > >>>> ODP_ABORT("illegal free"); > >>>> > >>>> That will capture bugs with double enqueue when you will try to > send > >>>> that packets. > >>>> > >>>> > >>>> If your case we should maintain somewhere array of packet handles > >> and > >>>> packet headers, > >>>> with unclear size depending how match reference we can have. And > >>>> handles > >>>> should not > >>>> overlap with current packet handles. That looks more complicated, > >>>> right? > >>>> > >>> Just like any other ODP API, this is a question of API definition > vs. > >> freedom of implementation. API spec defines two handles (one per > >> reference) and thus user must act as if those two handles are > unique, > >> BUT the implementation can choose if it reuses the handle value or > not. > >>> For example, > >>> > >>> typedef odp_packet_t soc_packet_descriptor_t *; > >>> > >>> > >>> odp_packet_t odp_packet_create_ref(odp_packet_t pkt) > >>> { > >>> soc_packet_descriptor_t *desc = (soc_packet_descriptor_t *) pkt; > >>> > >>> desc->ref_count++; > >>> return pkt; > >>> } > >> that variant is clear, but pkt on input and output is the same - > it's > >> pointer to desc somewhere. > >> But it's the same what I proposed. > >> > >>> OR > >>> > >>> odp_packet_t odp_packet_create_ref(odp_packet_t pkt) > >>> { > >>> soc_packet_descriptor_t *desc = ((soc_packet_descriptor_t *) pkt) > >> & PTR_MASK; > >>> desc->ref_count++; > >>> return (desc | > >> THIS_IS_A_REFERENCE_TO_A_PACKET_NOT_THE_ORIGINAL_PACKET_DESC); > >>> } > >> That variant modifies desc pointer. And there might be possible > issues: > >> > >> 1. it might not portable due to unable to restore original pointer > to > >> descr (if all bits of pointer address are used.). > >> 2. I assume some hw schedulers can unable to work with such modified > >> pointers. And it will be hard to implement in hw. > >> 3. On every function which works with packet you need clear > >> REFERENCE_BIT before accessing packet (access to *desc), > >> which is additional overhead. > > > > soc_packet_descriptor_t *desc = ((soc_packet_descriptor_t *) pkt) & > PTR_MASK; > > > > In this case: > > - handle = pointer + flags > > - pointer = handle - flags (the mask) > > - implementation passes the pointer to the HW, not the handle > > > > Handle can carry anything implementation needs, e.g. a flag which > distinguishes the original packet handle from additional references > (if that's import to the implementation). > > > > > > -Petri > > > > My point is - not everywhere you can do: > > - handle = pointer + flags > - pointer = handle - flags (the mask) > > > Let's say pointer uses 32 bits for address (PTR_MASK is 32 bit) handle > is also 32 bit. You just not have enough room > to save flags. > > Maxim.
It's OK since any implementation is not forced to save flags or return different handles for pkt and ref. Also in 32 bit systems you can - take advantage of descriptor alignment and/or memory map - and pack pointers to less than 32 bits - use indexes instead of pointers - define odp_packet_t as a structure of flags + pointer (e.g. sizeof struct can be 64 bits or more) Nothing special here, just use normal programming methods to pack information into a handle ==> into a structure that you can define. -Petri _______________________________________________ lng-odp mailing list lng-odp@lists.linaro.org https://lists.linaro.org/mailman/listinfo/lng-odp