lkml.org 
[lkml]   [1999]   [May]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
Subjectwritev() BUGS!


1. The following program hangs with VECTOR_COUNT set to high values
(greater than 16). It seems that Linux advertises a UIO_MAXIOV that is
large (1024) but it doesn't work for values that high.

Just compile the program and see for yourself. Then reset VECTOR_COUNT
to 16 and it works just fine.

% uname -a
Linux magic.highwind.com 2.2.5-15 #1 Mon Apr 19 23:00:46 EDT 1999 i686 unknown

I'm fairly sure this is in the latest kernel as well.


2. Although I do not have a test program for it, I am 100% sure that
even in the latest kernel, I sometimes see PARTIAL ::writev()'s of
data on blocking network connections.
Given that ::writev() on a blocking socket should never do
that, I suspect something isn't right in the networking code.
I wish this test program would show that problem,
unfortunately, it doesn't. However, I KNOW for a fact that I have seen
it. Perhaps some kind of signal logic interrupts writev(). I'm unsure.

In any case, ::writev() does sometimes perform a partial write
on a blocking socket, that is a BUG.

-Rob


------

/*****************************************************************************
File: writevTestLinux.C
Contents: writev() Bug Illustration
Created: 22-May-1999

Compile as:

g++ -Dlinux -D_REENTRANT -Wall -Werror -g -o writevTestLinux writevTestLinux.C -lpthread

Run as:
./writevTestLinux ip-address 9

(You run it against the "disgard" port (9) of a neighboring machine)

*****************************************************************************/

#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <memory.h>
#include <netinet/in.h>

#if defined(linux)
#include <poll.h>
#endif

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>

#define VECTOR_COUNT UIO_MAXIOV

unsigned int threadCount = 10;

static void *writeThread(void *arg)
{
// Get the fd to writev() from the argument
int fd = *(static_cast<int *>(arg));
delete arg;

// We are going to write 1024 x's on each component of the vector
char buf[1024];
::memset(buf, 'x', 1024);

// Initialize the vector
iovec *iov = new iovec[VECTOR_COUNT];
for (int i = 0; i < VECTOR_COUNT; ++i) {
iov[i].iov_base = buf;
iov[i].iov_len = 1024;
}

::printf("Starting writev() Loop.\n");
for (int x = 0; x < 10; ++x) {
int written = ::writev(fd, iov, VECTOR_COUNT);

// Because this is a BLOCKING "writev()" there are only 2
// valid return values:
// -1 == Some kind of error
// 1024 * VECTOR_COUNT == Success on writing everything
//
// ANY other return value indicates something is BROKEN!!!!
if (written == -1) {
::printf("::writev() returned an error! (%d)\n", errno);
delete [] iov;
return 0;
}

if (written != 1024 * VECTOR_COUNT) {
::printf("::writev() is SERIOUSLY BROKEN.\n"
"A blocking ::writev() of %d bytes returned %d bytes\n",
1024 * VECTOR_COUNT, written);
delete [] iov;
return 0;
}
}
::printf("Finished writev() Loop.\n");
delete [] iov;

return 0;
}

int main(int argc, char *argv[])
{
if (argc != 3) {
::printf("Run as %s ip-address port\n", argv[0]);
return EXIT_FAILURE;
}

::printf("Test Starting\n");
// Initialize network data structure
int fd = -1;
sockaddr_in location;
::memset(&location, 0, sizeof(location));
location.sin_family = AF_INET;
location.sin_addr.s_addr = ::inet_addr(argv[1]);
location.sin_port = htons(::strtoul(argv[2], 0, 10));

for (unsigned int k = 0; k < threadCount; ++k) {
// Connect to the target
assert((fd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1);
assert(::connect(fd, reinterpret_cast<sockaddr *>(&location),
sizeof(location)) != -1);

// Do one NON-threaded call just as a test
writeThread(new int(fd));

// Initialize Thread Attributes
pthread_t tid;
pthread_attr_t attr;
assert(!::pthread_attr_init(&attr));
assert(!::pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_DETACHED));
assert(!::pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM));
// Spawn the thread
assert(!::pthread_create(&tid, &attr, writeThread,
new int(fd)));
// Cleanup Thread Attributes
assert(!::pthread_attr_destroy(&attr));
}

// Just sleep for 15 seconds.
::printf("Waiting for Threads\n");
::poll(0, 0, 15 * 1000);

::printf("Test Exiting\n");
return EXIT_SUCCESS;
}


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:51    [W:0.053 / U:0.360 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site