diff options
author | Christian Grothoff <christian@grothoff.org> | 2007-08-18 11:24:24 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2007-08-18 11:24:24 +0000 |
commit | 6f1d61c647808174873f0f507ec215fa8512cb69 (patch) | |
tree | 7fd5beada8121741283d8f4ee9a5d8101abf9cbc | |
parent | ef59dec2cab29b3c9679f55eeb490e2e265b066e (diff) | |
download | libmicrohttpd-6f1d61c647808174873f0f507ec215fa8512cb69.tar.gz libmicrohttpd-6f1d61c647808174873f0f507ec215fa8512cb69.zip |
do not busy wait on responses from callbacks (with external select)
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | src/daemon/connection.c | 91 | ||||
-rw-r--r-- | src/daemon/internal.h | 9 | ||||
-rw-r--r-- | src/daemon/response.c | 20 |
4 files changed, 90 insertions, 36 deletions
@@ -1,7 +1,11 @@ | |||
1 | Sat Aug 18 03:06:09 MDT 2007 | 1 | Sat 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 | ||
6 | Wed Aug 15 01:46:44 MDT 2007 | 10 | Wed 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 | */ | ||
167 | static int | ||
168 | ready_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; |