Messages in this thread | | | Date | Sat, 22 May 1999 08:17:24 -0400 (EDT) | From | HighWind Software Information <> | Subject | writev() 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/
| |