aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2007-08-18 11:24:24 +0000
committerChristian Grothoff <christian@grothoff.org>2007-08-18 11:24:24 +0000
commit6f1d61c647808174873f0f507ec215fa8512cb69 (patch)
tree7fd5beada8121741283d8f4ee9a5d8101abf9cbc
parentef59dec2cab29b3c9679f55eeb490e2e265b066e (diff)
downloadlibmicrohttpd-6f1d61c647808174873f0f507ec215fa8512cb69.tar.gz
libmicrohttpd-6f1d61c647808174873f0f507ec215fa8512cb69.zip
do not busy wait on responses from callbacks (with external select)
-rw-r--r--ChangeLog6
-rw-r--r--src/daemon/connection.c91
-rw-r--r--src/daemon/internal.h9
-rw-r--r--src/daemon/response.c20
4 files changed, 90 insertions, 36 deletions
diff --git a/ChangeLog b/ChangeLog
index c362ed3a..a8dede6f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,11 @@
1Sat Aug 18 03:06:09 MDT 2007 1Sat Aug 18 03:06:09 MDT 2007
2 Check for out of memory when adding headers to 2 Check for out of memory when adding headers to
3 responses. Check for NULL key when looking 3 responses. Check for NULL key when looking
4 for headers. - CG 4 for headers. If a content reader callback
5 for a response returns zero (has no data yet),
6 do not possibly fall into busy waiting when
7 using external select (with internal selects
8 we have no choice). - CG
5 9
6Wed Aug 15 01:46:44 MDT 2007 10Wed Aug 15 01:46:44 MDT 2007
7 Extending API to allow timeout of connections. 11 Extending API to allow timeout of connections.
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
index 15a9be42..6735147a 100644
--- a/src/daemon/connection.c
+++ b/src/daemon/connection.c
@@ -156,6 +156,58 @@ MHD_need_100_continue (struct MHD_Connection *connection)
156} 156}
157 157
158/** 158/**
159 * Prepare the response buffer of this connection for
160 * sending. Assumes that the response mutex is
161 * already held. If the transmission is complete,
162 * this function may close the socket (and return
163 * MHD_NO).
164 *
165 * @return MHD_NO if readying the response failed
166 */
167static int
168ready_response (struct MHD_Connection *connection)
169{
170 int ret;
171 struct MHD_Response *response;
172
173 response = connection->response;
174 ret = response->crc (response->crc_cls,
175 connection->messagePos,
176 response->data,
177 MIN (response->data_buffer_size,
178 response->total_size - connection->messagePos));
179 if (ret == -1)
180 {
181 /* end of message, signal other side by closing! */
182 response->total_size = connection->messagePos;
183 CLOSE (connection->socket_fd);
184 connection->socket_fd = -1;
185 return MHD_NO;
186 }
187 response->data_start = connection->messagePos;
188 response->data_size = ret;
189 if (ret == 0)
190 {
191 /* avoid busy-waiting when using external select
192 (we assume that the main application will
193 wake up the external select once more data
194 is ready). With internal selects, we
195 have no choice; if the app uses a thread
196 per connection, ret==0 is likely a bug --
197 the application should block until data
198 is ready! */
199 if ((0 ==
200 (connection->daemon->
201 options & (MHD_USE_SELECT_INTERNALLY |
202 MHD_USE_THREAD_PER_CONNECTION))))
203 connection->response_unready = MHD_YES;
204 return MHD_NO;
205 }
206 connection->response_unready = MHD_NO;
207 return MHD_YES;
208}
209
210/**
159 * Obtain the select sets for this connection 211 * Obtain the select sets for this connection
160 * 212 *
161 * @return MHD_YES on success 213 * @return MHD_YES on success
@@ -205,7 +257,16 @@ MHD_connection_get_fdset (struct MHD_Connection *connection,
205 } 257 }
206 } 258 }
207 } 259 }
208 if ((connection->response != NULL) || MHD_need_100_continue (connection)) 260 if ((connection->response != NULL) &&
261 (connection->response_unready == MHD_YES))
262 {
263 pthread_mutex_lock (&connection->response->mutex);
264 ready_response (connection);
265 pthread_mutex_unlock (&connection->response->mutex);
266 }
267 if (((connection->response != NULL) &&
268 (connection->response_unready == MHD_NO)) ||
269 MHD_need_100_continue (connection))
209 { 270 {
210 FD_SET (fd, write_fd_set); 271 FD_SET (fd, write_fd_set);
211 if (fd > *max_fd) 272 if (fd > *max_fd)
@@ -1090,32 +1151,10 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1090 if ((response->crc != NULL) && 1151 if ((response->crc != NULL) &&
1091 ((response->data_start > connection->messagePos) || 1152 ((response->data_start > connection->messagePos) ||
1092 (response->data_start + response->data_size <= 1153 (response->data_start + response->data_size <=
1093 connection->messagePos))) 1154 connection->messagePos)) && (MHD_YES != ready_response (connection)))
1094 { 1155 {
1095 ret = response->crc (response->crc_cls, 1156 pthread_mutex_unlock (&response->mutex);
1096 connection->messagePos, 1157 return MHD_YES;
1097 response->data,
1098 MIN (response->data_buffer_size,
1099 response->total_size -
1100 connection->messagePos));
1101 if (ret == -1)
1102 {
1103 /* end of message, signal other side by closing! */
1104 response->total_size = connection->messagePos;
1105 CLOSE (connection->socket_fd);
1106 connection->socket_fd = -1;
1107 if (response->crc != NULL)
1108 pthread_mutex_unlock (&response->mutex);
1109 return MHD_YES;
1110 }
1111 response->data_start = connection->messagePos;
1112 response->data_size = ret;
1113 if (ret == 0)
1114 {
1115 if (response->crc != NULL)
1116 pthread_mutex_unlock (&response->mutex);
1117 return MHD_YES;
1118 }
1119 } 1158 }
1120 /* transmit */ 1159 /* transmit */
1121 ret = SEND (connection->socket_fd, 1160 ret = SEND (connection->socket_fd,
diff --git a/src/daemon/internal.h b/src/daemon/internal.h
index c4180d3b..353312b4 100644
--- a/src/daemon/internal.h
+++ b/src/daemon/internal.h
@@ -347,6 +347,15 @@ struct MHD_Connection
347 */ 347 */
348 unsigned int responseCode; 348 unsigned int responseCode;
349 349
350 /**
351 * Set to MHD_YES if the response's content reader
352 * callback failed to provide data the last time
353 * we tried to read from it. In that case, the
354 * write socket should be marked as unready until
355 * the CRC call succeeds.
356 */
357 int response_unready;
358
350}; 359};
351 360
352 361
diff --git a/src/daemon/response.c b/src/daemon/response.c
index 648b36a2..160246eb 100644
--- a/src/daemon/response.c
+++ b/src/daemon/response.c
@@ -53,16 +53,18 @@ MHD_add_response_header (struct MHD_Response *response,
53 if (hdr == NULL) 53 if (hdr == NULL)
54 return MHD_NO; 54 return MHD_NO;
55 hdr->header = strdup (header); 55 hdr->header = strdup (header);
56 if (hdr->header == NULL) { 56 if (hdr->header == NULL)
57 free(hdr); 57 {
58 return MHD_NO; 58 free (hdr);
59 } 59 return MHD_NO;
60 }
60 hdr->value = strdup (content); 61 hdr->value = strdup (content);
61 if (hdr->value == NULL) { 62 if (hdr->value == NULL)
62 free(hdr->header); 63 {
63 free(hdr); 64 free (hdr->header);
64 return MHD_NO; 65 free (hdr);
65 } 66 return MHD_NO;
67 }
66 hdr->kind = MHD_HEADER_KIND; 68 hdr->kind = MHD_HEADER_KIND;
67 hdr->next = response->first_header; 69 hdr->next = response->first_header;
68 response->first_header = hdr; 70 response->first_header = hdr;