3

In my development environment some of the ioctl calls are failing on the first time, if I am calling the same ioctl again then it returning success. This is because of some hardware related time synchronization issues.

So we are going for some temporary solution like masking all ioctl with one MACRO, inside that MACRO calling ioctl three times.

but that MACRO throws compilation error. Please suggest some solution to resolve this issue.

Sample Code

#include <stdio.h>

int func (int a, int b, int c)
{
    return -1;
}

#define IOCTL_WRAPPER(a,b,c)                    \
            {                                   \
                int i = 0, retval = 0;          \
                while (i < 3)                   \
                {                               \
                    retval = func (a, b, c);    \
                    if (retval != -1)           \
                    {                           \
                        break;                  \
                    }                           \
                    i++;                        \
                }                               \
                retval;                         \
            }

int main ()
{
    int RetVal = 0;

    RetVal = IOCTL_WRAPPER(1, 2, 3);

    if (RetVal != -1)
    {
        printf ("\n pass \n");
    }
    else
    {
        printf ("\n fail \n");
    }

    return 0;
}

Compilation Error

a.c: In function âmainâ:
a.c:9:13: error: expected expression before â{â token
             {                                   \
             ^
a.c:27:14: note: in expansion of macro âIOCTL_WRAPPERâ
     RetVal = IOCTL_WRAPPER(1, 2, 3);
          ^
nalzok
  • 14,965
  • 21
  • 72
  • 139
Hakkim Ansari
  • 119
  • 3
  • 10
  • We can't use function for this purpose because, simultaneous access of ioctl calls may cause issues. – Hakkim Ansari Mar 22 '16 at 09:37
  • 3
    That comment doesn't make sense, Hakkim. If using a function can result in simultaneous access of ioctl calls, so can a macro. Statements can only be executed in a function. – Peter Mar 22 '16 at 09:49
  • 3
    @HakkimAnsari Why do you need a macro ? Why can't you just wrap this in a normal function ? Your comment really doesn't make sens. This looks like an [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) to me. – Jabberwocky Mar 22 '16 at 09:53
  • 1
    It is mildly odd that your `IOCTL_WRAPPER` macro actually wraps `func` and not `ioctl`. Is this a change of mind while creating the question or an indication that you have a pointer to function that you're using to call `ioctl`? Could the problem be multiple threads modifying the function pointer? – Jonathan Leffler Mar 22 '16 at 12:49
  • 2
    "hardware related time synchronization issues" -- arbitrating safe concurrent access to the device is the responsibility of the code in the OS behind the `ioctl()`. You should make the case for addressing this problem there. Yes, I understand that it may be out of your domain of responsibility yet that's the most appropriate place to deliver a fix. – Brian Cain Mar 22 '16 at 13:00

2 Answers2

4

I would advise to use the do-while macro style to avoid futur problems. And to solve your problem, give the retVal as a parameter:

#define IOCTL_WRAPPER(retval, a,b,c)        \
        do {                                \
            int i = 0;                      \
            while (i < 3)                   \
            {                               \
                retval = func (a, b, c);    \
                if (retval != -1)           \
                {                           \
                    break;                  \
                }                           \
                i++;                        \
            }                               \
        } while(0)

And your call would be:

IOCTL_WRAPPER(RetVal, 1, 2, 3);
Puck
  • 2,080
  • 4
  • 19
  • 30
2

Your macro expands to a code block, which is not an expression.

Why not just use an inline function? Example code:

static inline int ioctl_wrapper(int a, int b, int c)
{
    int i = 0, retval = 0;
    while (i < 3)
    {
        retval = func (a, b, c);
        if (retval != -1)
        {
            break;
        }
        i++;
    }
    return retval;
}

Although ioctl_wrapper() is not necessary inlined, it's usually considered better to leave the optimisation job to your compiler(especially modern ones). If it thinks ioctl_wrapper() should not be inlined, using a macro to "force inline" may not be a good idea.


It suddenly occurs to me that there exists another extremely trivial approach:

retval = (func(a, b, c) + 1) || (func(a, b, c) + 1) || (func(a, b, c) + 1);

If the return value of one of the three calls isn't -1, retval would be 1; Otherwise, it'll be 0.

nalzok
  • 14,965
  • 21
  • 72
  • 139
  • 1
    Why `extern` and not `static`? I would use `static` and never `extern` with an inline function. – Jonathan Leffler Mar 22 '16 at 13:06
  • @JonathanLeffler Seems that either `extern` or `static` is OK. See: http://stackoverflow.com/a/216546/5399734 – nalzok Mar 22 '16 at 13:08
  • Syntactically, yes. Do you understand the semantics of the `extern`? It isn't straight-forward. – Jonathan Leffler Mar 22 '16 at 13:10
  • @JonathanLeffler I'm not sure... In fact, I've never written any C code distributing among multi files. Maybe you can provide me with some resources for reading? – nalzok Mar 22 '16 at 13:15
  • You've got the xref I would provide (you linked to it), or there might be another similar question on the topic. You're not obliged to change your answer, but your life will probably be simpler if you use `static` with `inline` — you don't have to worry about multiple (visible) definitions wrecking your linking. – Jonathan Leffler Mar 22 '16 at 13:21