study_20160808 study_20160808 - 3 months ago 9
Linux Question

select function may upate timeout parameter in linux.why it is 'may update'?

My operating system is Centos 6.4.

For select the linux programmer's manual says: "select may update the timeout parameter to indicate how much time was left...."

I wonder why it is 'may' rather than 'must'? Is there a system version or a kernel version?

I make a test.
test_code01.cpp

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <pthread.h>

#define BUFSIZE 1024

struct timeval g_timeout;

int main(int argc, char* argv[])
{
int sock_clientfd, ret_recvsize, i;
struct sockaddr_in dest, mine;
char buffer[BUFSIZE + 1];

// create socket fd
if ((sock_clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Socket");
exit(EXIT_FAILURE);
}

// init server address that client will connetct to.
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(9567);
if(argc != 2)
{
printf("Usage: %s <dest ip>\n", argv[0]);
printf("Usage: %s 127.0.0.1\n", argv[0]);
return -1;
}

printf("-----\n");

if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
{
perror(argv[1]);
exit(1);
}

// connect to server
printf("will connect!\n");
if (connect(sock_clientfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
{
perror("Connect ");
exit(EXIT_FAILURE);
}

int ret_select = 0;
fd_set readfds;
FD_SET(sock_clientfd, &readfds);

g_timeout.tv_sec = 3;
g_timeout.tv_usec = 0;

while(1)
{
ret_select = select(sock_clientfd + 1, &readfds, NULL, NULL, &g_timeout);

// Becasue select can update timeout, we need to set value for timeout.
// g_timeout.tv_sec = 3;
// g_timeout.tv_usec = 0;

// Recover sock_clienfd state
FD_SET(sock_clientfd, &readfds);

if(ret_select == 0)
{
printf("select wait timeout.\n");
continue;
}

bzero(buffer, BUFSIZE + 1);
ret_recvsize = recv(sock_clientfd, buffer, BUFSIZE, 0);
if(ret_recvsize > 0)
{
printf("get %d message:%s", strlen(buffer), buffer);
ret_recvsize=0;
}
else
{
printf("no data from server\n");
}
}

// close sock_clientfd
close(sock_clientfd);

return 0;
}


I execute this test_code01.cpp, and the result select wait for 3 seconds for only first times.In my opinion, the select modify timeout.So I modify code follow:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <pthread.h>

#define BUFSIZE 1024

// in order to facilitate the ovservation data
// the timeout is set to global varible
struct timeval g_timeout;

void* thredproc_looktimeout(void*)
{
while(1)
{
printf("left time: %ds %dms\n", g_timeout.tv_sec, g_timeout.tv_usec);
}
}

int main(int argc, char* argv[])
{
int sock_clientfd, ret_recvsize, i;
struct sockaddr_in dest, mine;
char buffer[BUFSIZE + 1];

// create socket fd
if ((sock_clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Socket");
exit(EXIT_FAILURE);
}

// init server address that client will connetct to.
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(9567);
if(argc != 2)
{
printf("Usage: %s <dest ip>\n", argv[0]);
printf("Usage: %s 127.0.0.1\n", argv[0]);
return -1;
}

printf("-----\n");

if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
{
perror(argv[1]);
exit(1);
}

// connect to server
printf("will connect!\n");
if (connect(sock_clientfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
{
perror("Connect ");
exit(EXIT_FAILURE);
}

int ret_select = 0;
fd_set readfds;
FD_SET(sock_clientfd, &readfds);
printf("fdset add fd start+++\n");
for(int i = 0; i < 2000; i++)
{
FD_SET(1025+i, &readfds);
}
printf("%d--%s\n", errno, strerror(errno));
printf("fdset add 2000 fd finish...\n");

g_timeout.tv_sec = 3;
g_timeout.tv_usec = 0;


/**
* look timeout left time by create thread
**/
pthread_t tid;
int ret_pthreadcreate = pthread_create(&tid, NULL, thredproc_looktimeout, NULL);
printf("pthread_create return value is %d\n", ret_pthreadcreate);

while(1)
{
ret_select = select(sock_clientfd + 1, &readfds, NULL, NULL, &g_timeout);

// Becasue select can update timeout, we need to set value for timeout.
g_timeout.tv_sec = 3;
g_timeout.tv_usec = 0;

// Recover sock_clienfd state
FD_SET(sock_clientfd, &readfds);

if(ret_select == 0)
{
printf("select wait timeout.\n");
continue;
}

bzero(buffer, BUFSIZE + 1);
ret_recvsize = recv(sock_clientfd, buffer, BUFSIZE, 0);
if(ret_recvsize > 0)
{
printf("get %d message:%s", strlen(buffer), buffer);
ret_recvsize=0;
}
else
{
printf("no data from server\n");
}
}

// close sock_clientfd
close(sock_clientfd);

return 0;
}


I think we should see a change in timeout in thredproc_looktimeout.But no change.I don't know why?

Answer

The manual page means that on return the timeout might be updated to indicate the amount of time left. It absolutely doesn't mean that the timeout will be updated while the wait is still in progress.

And even if it was, there is no possible way you could detect it. Your attempt to do with threads won't work because it has no synchronization of any kind. Among other problems, the compiler could optimize the while loop to read g_timeout only once. And there is no conceivable synchronization mechanism you could use.