Почему появился E2BIG после вызова msgrcv в SunOS, но те же самые коды работают нормально в Linux? - PullRequest
0 голосов
/ 23 марта 2012

После вызова msgrcv () я получил E2BIG: на SunOS, CPP-компилятор.

Вывод следующий:

arguments:
MsgID: 335006
pointer: 0xffbfbac8
sizeof: 1040
MsgType: 0
MsgFlag: 2048
RetVal=-1
RM: message waiting failed with error 7.

В руководстве:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

Маунал говорит, что для msgrcv () E2BIG получается, когда «длина текста сообщения больше, чем msgsz, а MSG_NOERROR не указан в msgflg.»

Но в моем случае, похоже, длина равна тексту сообщения. Кстати, как эта функция получит длину void * msgp? Это пустота.

Извините, я опубликовал длинный кусок кода, так как боюсь что-то пропустить. Спасибо.

EDIT:
Руководство говорит,

The msgp argument is a pointer to caller-defined structure of the  fol-
       lowing general form:

            struct msgbuf {
                long mtype;       /* message type, must be > 0 */
                char mtext[1];    /* message data */
            };

The  mtext  field is an array (or other structure) whose size is specified by msgsz, a non-negative integer value

Я добавил дополнительную информацию от gdb следующим образом: 227 RetVal = msgrcv (TDM_M [MyModule] .msg_id, 228 (void *) & SysMsg, 229 (size_t) sizeof (T_MSGBUF), 230 MsgType, 231 MsgFlag); 23 235 * / (gdb) p sizeof (SysMsg) 10 долларов США = 1044 (gdb) p sizeof (T_MSGBUF) 11 долларов США = 1040

Length - Размер пункта назначения = 4 (= размер long int), похоже, что он правильный. Кроме того, я обнаружил, что проблема происходит только с SunOS. Тот же код отлично работает в Linux.

Редактировать Я нашел основную причину. Подобно тому, как errno E2BIG, указывающее, что MsgLength меньше полученного сообщения, мой макрос отправки считает неправильное значение, которое должно было быть равно MsgLength в WAIT_MSG ().

Спасибо за ваш совет и ответы.

.h файл / * MSGBUF определен для конкретного сообщения * SysMsg определяется как arg для msgrcv * /

#define MSGBUF_SIZE     1040
#define MSGBODY_SIZE    (MSGBUF_SIZE)
#define MSGBODY_SIZE1   (MSGBUF_SIZE-16)

typedef struct {

   unsigned char        SrcModule;
   unsigned char        DstModule;
   unsigned char        MsgType;       

   unsigned short       SubMsgId;
   unsigned short       Length;
   long int             reserved;
} MsgHeader;

typedef struct _MsgBody {
   unsigned char Data[MSGBODY_SIZE1];
} MSGBODY;

typedef struct _MsgBuf {
   MsgHeader Header;             // the header of message.
   MSGBODY   Body;                   // the message body.
} MSGBUF;

typedef struct _MsgInside {
    long int        MsgType;
    MSGBUF          MsgText;
} SYS_MSG;

.cpp

int WaitMsg (DMMODULE        MyModule,
                MSGBUF*       pMsgBuf,
                long            MsgType,
                int             MsgFlag,
                TIME_USEC       abs_timeout)
{
   SYS_MSG      SysMsg;
   int          RetVal;

   ...

    memset(&SysMsg, 0, sizeof(SYS_MSG));


        printf("arguments:\n");
        printf("MsgID: %d\n", Module[MyModule].msg_id);
        printf("pointer: 0x%x\n", (void *)&SysMsg);
        printf("sizeof: %d\n",  (size_t)sizeof(T_MSGBUF));

         printf("MsgType: %d\n", MsgType);
        printf("MsgFlag: %d\n", MsgFlag);

    /* Module is a global array in which msg_id is storing */
    RetVal = msgrcv( Module [MyModule].msg_id,
                     (void *)&SysMsg,
                     (size_t)sizeof(MSGBUF),
                     MsgType,
                     MsgFlag);

    /* So far, only ENOMSG is handled, the rest is ignored,
     * Maybe a signal handler is needed later.
     */
    if( RetVal == -1 )
    {
        switch (errno)
        {
        case ENOMSG:
            return My_ENOMSG;

        case E2BIG:
        case EACCES:
        case EAGAIN:
        case EFAULT:
        case EIDRM:
        case EINTR:
        case EINVAL:

/* Here is where the error reported */

            printf("%s: message waiting failed with error %d.\n",
                     Module[MyModule].name, errno);
            printf("%s: \n", strerror(errno));

            return FAIL;

      default:

            printf("%s: message waiting failed with error %d.\n",
                     Module[MyModule].name, errno);
            printf("%s: \n", strerror(errno));

            return FAIL;
        }
    }

    memcpy(pMsgBuf, &(SysMsg.MsgText), sizeof(T_MSGBUF));


    printf("message is received by %s.\n",  Module[MyModule].name);


    return SUCC;

}

...
#define WAIT_MSG(MyModule,pMsgBuf,time_us )             \
        WaitMsg((MyModule),(pMsgBuf),0,IPC_NOWAIT,0)

int main()
{
   int rc = -1;
   MSGBUF    msgbuf; 

   rc = WAIT_MSG( RM, &msgbuf, 0 );
    ...
}

}

Ответы [ 3 ]

1 голос
/ 23 марта 2012

Ошибка E2BIG означает, что сообщение, которое вы пытаетесь получить, не помещается в ваш буфер. Вы должны сделать буфер больше. Ваш буфер составляет около 1020 или 1024 байта, я не уверен. Если входящее сообщение больше, вы получите E2BIG.

Кстати, как эта функция получает длину void * msgp? Это пустота.

Кажется, вам немного неясно, как работают указатели. Указатели просто указывают на одно место в памяти, они не имеют длины. (Даже не пустые указатели не имеют «длины».) Всякий раз, когда вы указываете область памяти, вы должны указать ее начальное местоположение (void *) и ее длину (size_t). Когда вы передаете диапазон памяти функции в C, длина обычно указывается одним из трех способов:

  1. Длина фиксирована. Например, когда вы вызываете setjmp, вы передаете указатель на область памяти длиной sizeof(jmp_buf) байт.
  2. Длина передается как отдельный аргумент. Например, fwrite или msgrcv.
  3. Длина определяется с помощью часового. Например, strlen.

Совет:

  1. Если вам нужно передать указатель как void *, не используйте приведение; это может скрыть ошибку в вашем коде, если вы случайно приведете не-указатель к void *. При необходимости указатели автоматически приводятся к void *.
  2. Результат sizeof всегда равен size_t, не разыгрывайте его. Это как писать (int)1, (double)0.5 или (const char [6])"Hello".
  3. Не используйте sizeof(type) для memcpy или msgrcv аргументов. Опечатки в memcpy аргументах являются распространенным источником ошибок, а обращение к удаленным типам затрудняет их обнаружение при чтении кода.

    // Not so good
    // Reading the code, I have to look for the definition of pMsgBuf
    // in order to know if sizeof(T_MSGBUF) is correct
    memcpy(pMsgBuf, &(SysMsg.MsgText), sizeof(T_MSGBUF));
    // Who knows if sizeof(MSGBUF) is correct?
    msgrcv(..., &SysMsg, sizeof(MSGBUF), ...);
    
    // Better
    // Reading the code, I know sizeof(*pMsgBuf) is correct,
    // but &(SysMsg.MsgText) might be a different type.
    memcpy(pMsgBuf, &(SysMsg.MsgText), sizeof(*pMsgBuf));
    msgrcv(..., &SysMsg, sizeof(SysMsg), ...);
    
    // Best
    // Most errors will be caught by the compiler.
    static void msgbuf_copy(MSGBUF *dest, const MSGBUF *src)
    { memcpy(dest, src, sizeof(*dest)); }
    
    msgbuf_copy(pMsgBuf, &SysMsg.MsgText);
    
  4. Если вы хотите, чтобы ваши сообщения имели размер 1024 байта, напишите это в коде. Не собирайте структуру, которая может содержать до 1024 байтов, сделайте это явно.

    typedef struct {
       unsigned char        SrcModule;
       unsigned char        DstModule;
       unsigned char        MsgType;       
    
       unsigned short       SubMsgId;
       unsigned short       Length;
       long int             reserved;
    } MsgHeader;
    
    typedef struct {
       MsgHeader Header;
       char Body[1024 - sizeof(MsgHeader)];
    } MSGBUF;
    
0 голосов
/ 23 марта 2012

Чтобы вычислить правильное значение msgsz, выполните sizeof(SysMsg) - sizeof(SysMsg.MsgType): вам необходимо вычесть поле long mtype буфера сообщений.И это должно быть сделано и в отправителе.

0 голосов
/ 23 марта 2012

Переменная SysMsg, переданная в msgrcv, имеет тип

typedef struct _MsgInside {
    long int        MsgType;
    MSGBUF          MsgText;
} SYS_MSG;

Вы пробовали что-то глупое и простое

typedef struct _MsgInside {
    long int        MsgType;
    char          MsgText[10000];
} SYS_MSG;

чтобы увидеть, изменит ли он свое поведение?

Редактировать, упс

Также поле размера sizeof(MSGBUF), но тип сообщения SYS_MSG

В лучшем случае это сбивает с толку; всегда используйте sizeof(var).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...