root/trunk/whisperlib/net/base/selectable.cc

Revision 7, 5.9 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Authors: Cosmin Tudorache & Catalin Popescu
31
32
33 #include "net/base/selectable.h"
34
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <sys/uio.h>
38 #include <sys/socket.h>
39
40 #include "common/base/errno.h"
41
42 namespace net {
43
44 int32 Selectable::Write(const char* buf, int32 size) {
45   const int32 cb = ::write(GetFd(), buf, size);
46   if ( cb <= 0 ) {
47     if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
48       // Not really an error for non-blocking sockets
49       return 0;
50     }
51     return -1;
52   }
53   return cb;
54 }
55
56 //////////////////////////////////////////////////////////////////////
57
58 // Is unclear so far if (and what) advantage seems to add writev
59 // to the overall performance..
60 //
61 // 10/6/2009:
62 // Updated note: apparently is better w/ new versions of kernel to use
63 //    writev (by some large margin..)
64 //
65 // #define __USE_WRITEV__
66 #ifdef  __USE_WRITEV__
67
68 //////////////////////////////////////////////////////////////////////
69
70 DEFINE_int32(default_read_for_writev_size, 16384,
71              "You can tune this in order to get some "
72              "better network performance");
73
74 //////////////////////////////////////////////////////////////////////
75
76 int32 Selectable::Write(io::MemoryStream* ms) {
77   int32 size = 0;
78   int32 cb = 0;
79 #ifdef _DEBUG
80   int64 initial_size = ms->Size();
81 #endif
82   const int fd = GetFd();
83
84   while ( !ms->IsEmpty() ) {
85     ms->MarkerSet();
86     struct ::iovec* iov = NULL;
87     int iovcnt = 0;
88     size = ms->ReadForWritev(&iov, &iovcnt,
89                              FLAGS_default_read_for_writev_size);
90     if ( iovcnt > 0 ) {
91       const ssize_t crt_cb = ::writev(fd, iov, iovcnt);
92       const int err = errno;
93       delete [] iov;
94       if ( crt_cb < 0 ) {
95         ms->MarkerRestore();
96         if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
97           // Not really an error for non-blocking sockets
98           DCHECK_EQ(initial_size, cb + ms->Size());
99           return cb;
100         }
101         return -1;
102       }
103       if ( crt_cb < size ) {
104         // Written something but not all - we need to return and mark
105         // the right ammount in the buffer
106         ms->MarkerRestore();
107         ms->Skip(crt_cb);
108       } else {
109         // Everything written - no need for the marker
110         ms->MarkerClear();
111       }
112       cb += crt_cb;
113       if ( crt_cb < size || err != 0 ) {
114         break;   // EAGAIN || EWOULDBLOCK
115       }
116     } else {
117       LOG_FATAL << "Dumb shit: " << size << " -- " << ms->Size();
118     }
119   }
120   DCHECK_EQ(initial_size, cb + ms->Size());
121   return cb;
122 }
123
124 //////////////////////////////////////////////////////////////////////
125
126 # else
127
128 int32 Selectable::Write(io::MemoryStream* ms) {
129   const char* buf;
130   int size = 0;
131   int32 cb = 0;
132   while ( !ms->IsEmpty() ) {
133     ms->MarkerSet();
134     size = 0;
135     CHECK(ms->ReadNext(&buf, &size))
136         << " bugs: unempty MemoryStream is unreadable."
137         << " ms " << ms->Size();
138     CHECK_GE(size, 0);
139     if ( size ) {
140       const int32 sent = Write(buf, size);
141       const int err = errno;
142       if ( sent <= 0 ) {
143         // Some error - nothing sent - restore the marker and bail out.
144         // (Error treated in underlying Write)
145         ms->MarkerRestore();
146         return cb;
147       } else if ( sent < size ) {
148         // Written something but not all - we need to return and mark
149         // the right ammount in the buffer
150         ms->MarkerRestore();
151         ms->Skip(sent);
152       } else {
153         // Everything written - no need for the marker
154         ms->MarkerClear();
155       }
156       cb += sent;
157       if ( sent < size && err != 0 ) {
158         break;   // EAGAIN || EWOULDBLOCK
159       }
160     }
161   }
162   // Basically the entire buffer was sent.
163   return cb;
164 }
165
166 #endif
167
168 //////////////////////////////////////////////////////////////////////
169
170 int32 Selectable::Read(char* buf, int32 size) {
171   const int32 cb = ::read(GetFd(), buf, size);
172   if ( cb <= 0 ) {
173     if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
174       // Not really an error for non-blocking sockets
175       return 0;
176     }
177     return -1;
178   }
179   return cb;
180 }
181
182 int32 Selectable::Read(io::MemoryStream* ms) {
183   char* buffer;
184   int32 size;
185   int32 cb = 0;
186   while ( true ) {
187     ms->GetScratchSpace(&buffer, &size);
188     const int32 received = Read(buffer, size);
189     const int err = errno;
190     if ( received <= 0 ) {
191       ms->ConfirmScratch(0);
192       return cb;
193     }
194     cb += received;
195     ms->ConfirmScratch(received);
196     if ( err ) {
197       return cb;   // EAGAIN || EWOULDBLOCK
198     }
199   }
200 }
201 }
Note: See TracBrowser for help on using the browser.