This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Problem with sl_Select() timeout functionality

Hi Experts,

We are using sl_Select() with timeout. Timeout seems to be working but not as expected/documented in the simplelink documentation. When we provide timeout and no data received within timeout interval, program comes out of select (as expected); however readfdset is not set to 0 (unexpected). This gives an impression to the application that there is data on the socket application tries to read the data and blocks. This beats the purpose of using select().

As per simplelink documentation, in case of timeout readfdset must have been set to 0. Is this a defect in select() implementation?

From Documentation

Returns
    On success, select() returns the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything interesting happens. On error, a negative value is returned. readsds - return the sockets on which Read request will return without delay with valid data. writesds - return the sockets on which Write request will return without delay. exceptsds - return the sockets closed recently. SL_POOL_IS_EMPTY may be return in case there are no resources in the system In this case try again later or increase MAX_CONCURRENT_ACTIONS

  • Vipin,

    I'll reproduce it on my setup and get back.

    -Praneet

  • 3107.select-bug.zip

    Hi Praneet,

    To help you with reproducer, I am attaching the test case to reproduce the issue. It is based on UDP though I am using TCP in my application but since problem seems in select so it is visible in both UDP and TCP.

    This test case is based on udp-socket example. I am setting up udp server and then wait it select for 20 second timeout value. After timeout select unblock and code checks the fdset by using standard macro (SL_FD_ISSET(iSockID, &readSet)) which returns 1. In case of timeout I believe this macro must return 0.


    In if-else condition based on this macro instead of printing "Select Timed out" this tests prints "Data on Socket. Read it"

    How to run the reproducer test case

    1. Unzip attached zip file in SDK example folder.

    2. Import CCS project. Project name is select-bug

    3. Build and Run it. There is no data on UDP server. Select Timed out (expected), SL_FD_ISSET does not return 0 (unexpected).

    Hope with this reproducer you can confirm if this is a bug or not and suggest some workaround/patch.

  • Vipin,

    I suggest you check for the return-code as well which lists the number of bits that are set in readfds, writefds or exceptfds. If the return code is zero, then there is no data available, irrespective of the value in readfds - Below is the code snippet for doing it (modified 'BsdTcpServer' of example\tcp_socket). I'll as wel discuss the issue w/ readfds (value not being set to 0 when the return value of 'sl_Select' is 0) internally and see if can be fixed for the next SDK.

    -Praneet

    int BsdTcpServer(unsigned short usPort)
    {
        SlSockAddrIn_t  sAddr;
        SlSockAddrIn_t  sLocalAddr;
        int             iCounter;
        int             iAddrSize;
        int             iSockID;
        int             iStatus;
        int             iNewSockID;
        long            lLoopCount = 0;
        long            lNonBlocking = 1;
        int             iTestBufLen;
    
        SlFdSet_t ReadFds;
        SlFdSet_t ActiveReadFds;
        SlTimeval_t         timeout;
    
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
    
        SL_FD_ZERO(&ReadFds);
    
        // filling the buffer
        for (iCounter=0 ; iCounter<BUF_SIZE ; iCounter++)
        {
            g_cBsdBuf[iCounter] = (char)(iCounter % 10);
        }
    
        iTestBufLen  = BUF_SIZE;
    
        //filling the TCP server socket address
        sLocalAddr.sin_family = SL_AF_INET;
        sLocalAddr.sin_port = sl_Htons((unsigned short)usPort);
        sLocalAddr.sin_addr.s_addr = 0;
    
        // creating a TCP socket
        iSockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0);
        if( iSockID < 0 )
        {
            // error
            ASSERT_ON_ERROR(TCP_SERVER_FAILED);
        }
    
        SL_FD_SET(iSockID, &ReadFds);
    
        iAddrSize = sizeof(SlSockAddrIn_t);
    
        // binding the TCP socket to the TCP server address
        iStatus = sl_Bind(iSockID, (SlSockAddr_t *)&sLocalAddr, iAddrSize);
        if( iStatus < 0 )
        {
            // error
            ASSERT_ON_ERROR(sl_Close(iSockID));
            ASSERT_ON_ERROR(TCP_SERVER_FAILED);
        }
    
        // putting the socket for listening to the incoming TCP connection
        iStatus = sl_Listen(iSockID, 0);
        if( iStatus < 0 )
        {
            ASSERT_ON_ERROR(sl_Close(iSockID));
            ASSERT_ON_ERROR(TCP_SERVER_FAILED);
        }
    
        // setting socket option to make the socket as non blocking
        iStatus = sl_SetSockOpt(iSockID, SL_SOL_SOCKET, SL_SO_NONBLOCKING,
                                &lNonBlocking, sizeof(lNonBlocking));
        if( iStatus < 0 )
        {
            ASSERT_ON_ERROR(sl_Close(iSockID));
            ASSERT_ON_ERROR(TCP_SERVER_FAILED);
        }
        iNewSockID = SL_EAGAIN;
    
        // waiting for an incoming TCP connection
        while( iNewSockID < 0 )
        {
            // accepts a connection form a TCP client, if there is any
            // otherwise returns SL_EAGAIN
            iNewSockID = sl_Accept(iSockID, ( struct SlSockAddr_t *)&sAddr,
                                    (SlSocklen_t*)&iAddrSize);
            if( iNewSockID == SL_EAGAIN )
            {
               MAP_UtilsDelay(10000);
            }
            else if( iNewSockID < 0 )
            {
                // error
                ASSERT_ON_ERROR(sl_Close(iNewSockID));
                ASSERT_ON_ERROR(sl_Close(iSockID));
                ASSERT_ON_ERROR(TCP_SERVER_FAILED);
            }
        }
    
        SL_FD_SET(iNewSockID, &ReadFds);
    
        while(1)
        {
            ActiveReadFds = ReadFds;
            iStatus = sl_Select(iNewSockID + 1, &ActiveReadFds, NULL, \
                                       NULL, &timeout);
            if (iStatus > 0)
            {
                iStatus = sl_Recv(iNewSockID, g_cBsdBuf, iTestBufLen, 0);
                if( iStatus <= 0 )
                {
                    // error
                    ASSERT_ON_ERROR( sl_Close(iNewSockID));
                    ASSERT_ON_ERROR(sl_Close(iSockID));
                    ASSERT_ON_ERROR(TCP_SERVER_FAILED);
                }
            }
        }
    
        // close the connected socket after receiving from connected TCP client
        ASSERT_ON_ERROR(sl_Close(iNewSockID));
    
        // close the listening socket
        ASSERT_ON_ERROR(sl_Close(iSockID));
    
        Report("Recieved %u packets successfully\n\r",g_ulPacketCount);
    
        return SUCCESS;
    }

  • Hi Praneet,

    Thanks for your suggestion. Its working fine.