[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 1/2] block: enhance QEMUIOVector structure
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
Re: [Qemu-devel] [PATCH 1/2] block: enhance QEMUIOVector structure |
Date: |
Wed, 30 Jan 2019 15:52:21 +0000 |
30.01.2019 17:55, Eric Blake wrote:
> On 1/30/19 3:14 AM, Vladimir Sementsov-Ogievskiy wrote:
>> 30.01.2019 0:35, Eric Blake wrote:
>>> On 1/29/19 8:37 AM, Vladimir Sementsov-Ogievskiy wrote:
>>>> Add a possibility of embedded iovec, for cases when we need only one
>>>> local iov.
>>>>
>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <address@hidden>
>>>> ---
>>>> include/qemu/iov.h | 41 ++++++++++++++++++++++++++++++++++++++++-
>>>> 1 file changed, 40 insertions(+), 1 deletion(-)
>
>>> POSIX does not guarantee that iov_base occurs prior to iov_len in struct
>>> iovec; your code is therefore rather fragile and would fail to compile
>>> if we encounter a libc where iov_len is positioned differently than in
>>> glibc, tripping the first assertion. For an offset other than 0, you
>>> could declare:
>>> char [offsetof(struct iovec, iov_len)] __pad;
>>> to be more robust; but since C doesn't like 0-length array declarations,
>>> I'm not sure how you would cater to a libc where iov_len is at offset 0,
>>
>> Hmm, tested a bit, and the only complain I can get is a warning about 0-sized
>> array when option -pedantic is set. So, is it a real problem?
>
> Even if we require the use of gcc extensions elsewhere, it doesn't hurt
> to avoid them where it is easy.
>
>>
>> And we already have a lot of zero-sized arrays in Qemu, just look at
>> git grep '\w\+\s\+\w\+\[0\];' | grep -v return
>
> And how many of those are the last entry in a struct? A 0-size array at
> the end is a common idiom for a flex-sized struct (without relying on
> C99 VLA); a 0-size array in the middle of a struct is unusual.
Reasonable, so ...
>
>>
>>
>> hm, or we can do like this:
>>
>> typedef struct QEMUIOVector {
>> struct iovec *iov;
>> int niov;
>> union {
>> struct {
>> int nalloc;
>> struct iovec local_iov;
>> };
>> struct {
>> char __pad[sizeof(int) + offsetof(struct iovec, iov_len)];
>> size_t size;
>> };
>> };
>> } QEMUIOVector;
>
> Yes, that's a reasonable way to do it.
... will try this in v2, if no more comments.
>
>>
>>
>>> short of a configure probe and #ifdeffery, which feels like a bit much
>>> to manage (really, the point of the assert is that we don't have to
>>> worry about an unusual libc having a different offset UNLESS the build
>>> fails, so no need to address a problem we aren't hitting yet).
>>
>> However, char __pad[offsetof(struct iovec, iov_len)]; seems useful and even
>> more self-documented, so I'll use it in v2, if nobody minds.
>>
>
> We'll see how it looks, then.
>
>
>>>> + .iov_base = (void *)(buf), \
>>>
>>> Why is the cast necessary? Are we casting away const?
>
> Answered in 2/2 - yes. But a comment about /* cast away const */ is useful.
>
>>> Since C already
>>> allows assignment of any other (non-const) pointer to void* without a
>>> cast, it looks superfluous.
>>>
>>>> + .iov_len = len \
>>>
>>> Missing () around len.
>>
>> For style? What the thing len should be to break it without ()?
>
> Although we are unlikely to hit this given our coding conventions,
> remember that '=' has higher precedence than ',', for this contorted
> example (and yes, it's contorted because you can't pass the comma
> operator through to a macro without either supplying your own (), which
> defeats the demonstration, or relying on a helper macro such as
> raw_pair() here):
>
> $ cat foo.c
> struct s {
> int i;
> };
> #define raw_pair(a, b) a, b
> #define A(arg) { .i = (arg) }
> #define B(arg) { .i = arg }
>
> int
> main(int argc, char **argv)
> {
> struct s s1 = A(raw_pair(1, 2));
> struct s s2 = B(raw_pair(4, 8));
> return s1.i + s2.i;
> }
> $ gcc -o foo foo.c
> foo.c: In function ‘main’:
> foo.c:12:33: warning: excess elements in struct initializer
> struct s s2 = B(raw_pair(4, 8));
> ^
> foo.c:6:23: note: in definition of macro ‘B’
> #define B(arg) { .i = arg }
> ^~~
> foo.c:12:21: note: in expansion of macro ‘raw_pair’
> struct s s2 = B(raw_pair(4, 8));
> ^~~~~~~~
> foo.c:12:33: note: (near initialization for ‘s2’)
> struct s s2 = B(raw_pair(4, 8));
> ^
> foo.c:6:23: note: in definition of macro ‘B’
> #define B(arg) { .i = arg }
> ^~~
> foo.c:12:21: note: in expansion of macro ‘raw_pair’
> struct s s2 = B(raw_pair(4, 8));
> ^~~~~~~~
> $ ./foo; echo $?
> 6
>
> which says that for A() using the (), there were no warnings and the
> second value was assigned (-Wall changes that, complaining about unused
> value of the left side of the comma operator - but that's okay); but for
> B() without (), there was a diagnostic even without -Wall about too many
> initializers, and the first value was assigned.
Oh, that's cool!
>
>>> Why both a macro and a function that uses the macro?
>
> Also answered in 2/2 - the macro is for variable declarations; the
> function is for runtime code such as for-loops that start with an
> uninitialized declaration and have to reinitialize things. They also
> differ in that one takes a struct, the other takes a pointer to a struct.
>
>
--
Best regards,
Vladimir
[Qemu-devel] [PATCH 2/2] block/io: use qemu_iovec_init_buf, Vladimir Sementsov-Ogievskiy, 2019/01/29