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.

CC3220SF: How to unblock sl_Select with indefinite timeout?

Part Number: CC3220SF


Hi support,

Under what conditions will sl_Select return?  When I close a socket in the read_fd list?

How can I unblock it from application code?  Since we can only call sl_Select from one thread (task),  I  need to add new sockets to the list sometimes.  To do so, I need to unblock the previous call.  How would one do this?

Thanks!

  • Just adding some more info:

    We cannot use a polling mechanism on select.  We do not want to wake up when we do not need to.

    We cannot use trigger mode events via SimpleLinkSocketTriggerEventHandler, as we are running a multi-threaded RTOS.

    Thanks!

  • Perhaps we can call sl_Select from more than one task?

    After reading this thread: e2e.ti.com/.../2419780

    I assumed we couldn't.

    But a comment in sl_socket.h of sdk 2.4 says otherwise:

    Several threads can call sl_Select at the same time.\b
    Calling this API while the same command is called from another thread, may result
    in one of the following scenarios:
    1. The command will be executed alongside other select callers (success).
    2. The command will wait (internal) until the previous sl_select finish, and then be executed.
    3. There are not enough resources and SL_POOL_IS_EMPTY error will return.
    In this case, MAX_CONCURRENT_ACTIONS can be increased (result in memory increase) or try
    again later to issue the command.

    Even if this is true, it might be nice to have them just one select() task that can handle all sockets. So I would still like an answer to my questions above.
  • Hi Ben,

    Why don't you use non-blocking mode?

    Jesu
  • We cannot use a non-blocking (polling) mechanism on select, because the application is very power sensitive.
  • Hi Ben,

    Why don't you put all sockets on the list?

    EDIT:

    All sockets you care about of course.


    Jesu

  • Hi Jesu,

    Thanks for the suggestion.

    That's exactly what we want to do, but here is the scenario:

    Open socket 1, add it to the select() read_fd list.

    Call sl_select() with the read_fd list, with no timeout.

    Now from another task we open socket 2, and want to add it to the select() read_fd list.

    Since the sl_select() task is still blocked since no data has come in yet for socket 1, I can't add it to the new list!

    So how do I unblock sl_select() from application code? It's only looking for socket 1 at this point, and will not return until data has come in to socket 1. Am I forced to close socket 1 so sl_select will return?

    Thanks
  • Hi Ben,

    Closing socket to return from sl_Select is not a good idea. Even if it returns it's not a "graceful" way of handling things.

    What SDK are you using? After chatting with another engineer I found out that we do support multiple select calls in some later SDKs (not sure how far back). I verified that v2.2 and later supports this.

    Jesu
  • Hi Jesu,

    Agreed, it's not graceful. We're on SDK v2.4, so I have read in the release notes multiple selects became supported some time in 2018 . I went back through all of them. I think it begins in v2.1. or v1.6.

    We don't want to do multiple tasks since each socket will need a receive task. Too much overhead.

    We are going to try and implement the self pipe trick detailed here:
    stackoverflow.com/.../how-to-signal-select-to-return-immediately
    The plan to unblock select at present is to use an opened yet unbinded "dummy" UDP socket in every select call. If we need to unblock select, we'll close this socket. Obviously we'll need to reopen it every time we need to unblock it this way.
    e2e.ti.com/.../2929735
    It's not done yet but I'll let you know if it works. Please let me know if technically you think the SDK cannot support this functionality. If it can't, I would argue that it should, if it wants to be BSD compliant.
  • Hi Ben,

    I wonder if you could use the loopback address in sendTo to return sl_Select.

    Jesu

  • Also, you do not have to create an additional task for another sl_Select call. The host driver handles all of that in the background.

    EDIT: I guess you will still need one to handle the return. Never mind....


    Jesu

  • That's an interesting idea. But how can we get the loopback socket descriptor so that we can include it in the select read_fd list?  I see loopback address is 127.0.0.1.  What port should we connect to?

  • Hey Ben,

    Not sure what your question is. Are you using a TCP server socket? If so, add it to read_fd on sl_Select if you haven't already and just create a "dummy" socket that will try to connect to 127.0.0.1 on whatever port you're using to return from sl_Select.

    Jesu
  • Hi,

    Maybe I forgot for something, but I think loopback is not supported at CC32xx devices. let me correct if I am wrong.

    Jan
  • Hi everyone,

    Jan: I have not seen any document to indicate loopback is not supported but to your point I also haven't seen it being mentioned.

    I could confirm that trying to connect a client socket to the loopback address causes a return from sl_Select.

    Jesu
  • Hi Jesu,

    Thanks for the suggestion. I'd prefer not to go this route, but we might have to. We actually aren't using a listening server socket right now. We connect to a server, then just keep the socket open and wait for data from the server.

    My method of closing an unbound UDP socket that is included in the select() list doesn't seem to work, which is definitely unexpected. When I close it, select gets no indication of it. It's still blocked waiting for data.

    But actually more concerning is that if I call sl_Close() on the TCP socket that is being actively selected on (again, in a blocking manner with no timeout), this won't unblock select() either! This surely can't sound right to you, right? If I close a socket, one that is in the read_fd list(), select() should return immediately, right?

    I've verified this isn't a problem with our select task implementation. If I send real data to the socket, select() returns as expected.

  • Hi Jesu,

    Can you go into more detail about how you got select to unblock with a listener and dummy socket?

    For example:

    Server:

    LocalAddr.sin_family = SL_AF_INET;
    LocalAddr.sin_port = SOCKETS_htons( 5001 );
    LocalAddr.sin_addr.s_addr = 0;

    AddrSize = sizeof(SlSockAddrIn_t);

    unblock_select_socket = (void *)(sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0));

    status = sl_Bind((int)unblock_select_socket, (SlSockAddr_t *)&LocalAddr, AddrSize);

    status = sl_Listen((int)unblock_select_socket, 0);

    Dummy:

    Socket_t temporary_select_socket = sl_Socket(SOCKETS_AF_INET, SOCKETS_SOCK_STREAM, SOCKETS_IPPROTO_TCP);

    SocketsSockaddr_t local_addr = { 0 };
    local_addr.ulAddress =SlNetUtil_inetPton( "127.0.0.1" );
    local_addr.ucSocketDomain = SOCKETS_AF_INET;
    local_addr.usPort = SOCKETS_htons( 5001 );

    int status = sl_Connect(temporary_select_socket, &local_addr, sizeof(local_addr));

    Is this the right IP address to connect to for the loopback address? sl_Connect fails to connect to the server socket.

  • Hi Ben,

    The behavior you're seeing is expected for our implementation of sl_Select.

    Below is server socket code:

    Addr.sin_family = SL_AF_INET;
        Addr.sin_port = sl_Htons(5001);
        Addr.sin_addr.s_addr = SL_INADDR_ANY;
    
        sd = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0);
        if(sd < 0){
            Display_printf(display, 0, 0, "\n\rCould not create socket\r\n");
        }
    
        int16_t serverSock = sd;
    
        stat = sl_Bind(serverSock, ( SlSockAddr_t *)&Addr, sizeof(SlSockAddrIn_t));
        if(stat < 0)
        {
            Display_printf(display, 0, 0, "\n\rCould not bind socket\r\n");
        }
    
        stat = sl_Listen(serverSock, 1);
        if(stat < 0){
            Display_printf(display, 0, 0, "\n\rCould not listen socket\r\n");
        }
    
        SlFdSet_t rxSet;
    
        SL_SOCKET_FD_ZERO( &rxSet );
        SL_SOCKET_FD_SET(serverSock, &rxSet);
    
        Display_printf(display, 0, 0, "calling sl_select\r\n");
        stat = sl_Select(serverSock+1, &rxSet, NULL, NULL, NULL);
    
        while(1){
            Display_printf(display, 0, 0, "returned from sl_Select: %d\r\n", stat);
            sleep(1);
        }

    Below is "dummy" socket code to trigger return running in separate task:

    SlSockAddrIn_t Addr;
    
        Addr.sin_family = SL_AF_INET;
        Addr.sin_port = sl_Htons(5001);
        Addr.sin_addr.s_addr = sl_Htonl(SL_IPV4_VAL(127,0,0,1));
    
        sleep(5);
    
        int16_t sd = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0);
        if(sd < 0){
            Display_printf(display, 0, 0, "second socket create failed\r\n");
        }
        else{
            Display_printf(display, 0, 0, "second socket CREATED\r\n");
        }
    
        int16_t stat = sl_Connect(sd, ( SlSockAddr_t *)&Addr, sizeof(SlSockAddrIn_t));
        if(stat < 0){
            Display_printf(display, 0, 0, "\n\rcould not connect second socket: %d\r\n", stat);
        }
    
        while(1){
            sleep(1);
        }

    Jesu

  • Hi Jesu,

    Thanks for the clarification.

    I verified your method can be used to unblock select(), so I will mark this thread as resolved. I'm happy we found a way.

    I will say that this mechanism feels more like a hack than a feature. Is it planned for any future SDK's to have sl_Select behavior match BSD sockets more closely, perhaps allowing for exceptfds set to return closed sockets?

    I only ask this because we will now have to override our sl_Close routines to add extra logic to take care of cleaning them out of our select() task. We will have to unblock the task ourselves to remove them. There may be other situations I haven't accounted for too which would seemingly be cleared up by adding this functionality to sl_Select. For example, if we have a wlan disconnect event, I think we will have to do the same unblocking mechanism. If we called sl_Stop, I think we will have to do the same thing. You can see how complicated this quickly gets. It would be much easier if the call on sl_Select would return when any of these events happen which would invalidate the socket being waited on.

    Additionally, it is rather frustrating to learn this unique behavior by trial and error.  Of course I'm not blaming you for this as I know the SDK is constantly being updated and new features are being added.  But this sort of behavior is not documented anywhere I've seen so far.  All I have read is that the sl_ socket calls should act as BSD sockets, no? And this is clearly not the case here.  So in my opinion, a note of this should be made in the documentation.

    Either way, thanks again!

    Ben

  • Hi Ben,

    Glad I could help you find a way. I apologize for any confusion our documentation may have caused. To help clear things up our programmer's guide mentions our socket implementation supports BSD-compliant APIs - this does not speak to the implementation directly. Unfortunately we do not support exceptfds and as far as I know the SDK team does not intend to add it in the near future; I also do not see how it would be useful in your case. From what I gather it's mainly used to handle "out of band" data which admittedly I'm still trying to understand what that is.

    Naturally you could expect some differences in the behavior considering the resource and performance constraints of our device compared to a "full-on" PC and for these reasons I believe we cannot claim exact behavior nor intend to.

    Jesu