46
46
#include "connect.h"
47
47
#include "http_proxy.h"
48
48
#include "http2.h"
49
+ #include "socketpair.h"
49
50
/* The last 3 #include files should be in this order */
50
51
#include "curl_printf.h"
51
52
#include "curl_memory.h"
@@ -367,6 +368,21 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
367
368
368
369
/* -1 means it not set by user, use the default value */
369
370
multi -> maxconnects = -1 ;
371
+
372
+ #ifdef ENABLE_WAKEUP
373
+ if (Curl_socketpair (AF_UNIX , SOCK_STREAM , 0 , multi -> wakeup_pair ) < 0 ) {
374
+ multi -> wakeup_pair [0 ] = CURL_SOCKET_BAD ;
375
+ multi -> wakeup_pair [1 ] = CURL_SOCKET_BAD ;
376
+ }
377
+ else if (curlx_nonblock (multi -> wakeup_pair [0 ], TRUE) < 0 ||
378
+ curlx_nonblock (multi -> wakeup_pair [1 ], TRUE) < 0 ) {
379
+ sclose (multi -> wakeup_pair [0 ]);
380
+ sclose (multi -> wakeup_pair [1 ]);
381
+ multi -> wakeup_pair [0 ] = CURL_SOCKET_BAD ;
382
+ multi -> wakeup_pair [1 ] = CURL_SOCKET_BAD ;
383
+ }
384
+ #endif
385
+
370
386
return multi ;
371
387
372
388
error :
@@ -1005,7 +1021,8 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
1005
1021
unsigned int extra_nfds ,
1006
1022
int timeout_ms ,
1007
1023
int * ret ,
1008
- bool extrawait ) /* when no socket, wait */
1024
+ bool extrawait , /* when no socket, wait */
1025
+ bool use_wakeup )
1009
1026
{
1010
1027
struct Curl_easy * data ;
1011
1028
curl_socket_t sockbunch [MAX_SOCKSPEREASYHANDLE ];
@@ -1059,6 +1076,12 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
1059
1076
curlfds = nfds ; /* number of internal file descriptors */
1060
1077
nfds += extra_nfds ; /* add the externally provided ones */
1061
1078
1079
+ #ifdef ENABLE_WAKEUP
1080
+ if (use_wakeup && multi -> wakeup_pair [0 ] != CURL_SOCKET_BAD ) {
1081
+ ++ nfds ;
1082
+ }
1083
+ #endif
1084
+
1062
1085
if (nfds > NUM_POLLS_ON_STACK ) {
1063
1086
/* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
1064
1087
big, so at 2^29 sockets this value might wrap. When a process gets
@@ -1117,6 +1140,14 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
1117
1140
++ nfds ;
1118
1141
}
1119
1142
1143
+ #ifdef ENABLE_WAKEUP
1144
+ if (use_wakeup && multi -> wakeup_pair [0 ] != CURL_SOCKET_BAD ) {
1145
+ ufds [nfds ].fd = multi -> wakeup_pair [0 ];
1146
+ ufds [nfds ].events = POLLIN ;
1147
+ ++ nfds ;
1148
+ }
1149
+ #endif
1150
+
1120
1151
if (nfds ) {
1121
1152
int pollrc ;
1122
1153
/* wait... */
@@ -1140,6 +1171,29 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
1140
1171
1141
1172
extra_fds [i ].revents = mask ;
1142
1173
}
1174
+
1175
+ #ifdef ENABLE_WAKEUP
1176
+ if (use_wakeup && multi -> wakeup_pair [0 ] != CURL_SOCKET_BAD ) {
1177
+ if (ufds [curlfds + extra_nfds ].revents & POLLIN ) {
1178
+ char buf [64 ];
1179
+ while (1 ) {
1180
+ /* the reading socket is non-blocking, try to read
1181
+ data from it until it receives an error (except EINTR).
1182
+ In normal cases it will get EAGAIN or EWOULDBLOCK
1183
+ when there is no more data, breaking the loop. */
1184
+ if (sread (multi -> wakeup_pair [0 ], buf , sizeof (buf )) < 0 ) {
1185
+ #ifndef USE_WINSOCK
1186
+ if (EINTR == SOCKERRNO )
1187
+ continue ;
1188
+ #endif
1189
+ break ;
1190
+ }
1191
+ }
1192
+ /* do not count the wakeup socket into the returned value */
1193
+ retcode -- ;
1194
+ }
1195
+ }
1196
+ #endif
1143
1197
}
1144
1198
}
1145
1199
@@ -1174,7 +1228,8 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
1174
1228
int timeout_ms ,
1175
1229
int * ret )
1176
1230
{
1177
- return Curl_multi_wait (multi , extra_fds , extra_nfds , timeout_ms , ret , FALSE);
1231
+ return Curl_multi_wait (multi , extra_fds , extra_nfds , timeout_ms , ret , FALSE,
1232
+ FALSE);
1178
1233
}
1179
1234
1180
1235
CURLMcode curl_multi_poll (struct Curl_multi * multi ,
@@ -1183,7 +1238,55 @@ CURLMcode curl_multi_poll(struct Curl_multi *multi,
1183
1238
int timeout_ms ,
1184
1239
int * ret )
1185
1240
{
1186
- return Curl_multi_wait (multi , extra_fds , extra_nfds , timeout_ms , ret , TRUE);
1241
+ return Curl_multi_wait (multi , extra_fds , extra_nfds , timeout_ms , ret , TRUE,
1242
+ TRUE);
1243
+ }
1244
+
1245
+ CURLMcode curl_multi_wakeup (struct Curl_multi * multi )
1246
+ {
1247
+ /* this function is usually called from another thread,
1248
+ it has to be careful only to access parts of the
1249
+ Curl_multi struct that are constant */
1250
+
1251
+ /* GOOD_MULTI_HANDLE can be safely called */
1252
+ if (!GOOD_MULTI_HANDLE (multi ))
1253
+ return CURLM_BAD_HANDLE ;
1254
+
1255
+ #ifdef ENABLE_WAKEUP
1256
+ /* the wakeup_pair variable is only written during init and cleanup,
1257
+ making it safe to access from another thread after the init part
1258
+ and before cleanup */
1259
+ if (multi -> wakeup_pair [1 ] != CURL_SOCKET_BAD ) {
1260
+ char buf [1 ];
1261
+ buf [0 ] = 1 ;
1262
+ while (1 ) {
1263
+ /* swrite() is not thread-safe in general, because concurrent calls
1264
+ can have their messages interleaved, but in this case the content
1265
+ of the messages does not matter, which makes it ok to call.
1266
+
1267
+ The write socket is set to non-blocking, this way this function
1268
+ cannot block, making it safe to call even from the same thread
1269
+ that will call Curl_multi_wait(). If swrite() returns that it
1270
+ would block, it's considered successful because it means that
1271
+ previous calls to this function will wake up the poll(). */
1272
+ if (swrite (multi -> wakeup_pair [1 ], buf , sizeof (buf )) < 0 ) {
1273
+ int err = SOCKERRNO ;
1274
+ int return_success ;
1275
+ #ifdef USE_WINSOCK
1276
+ return_success = WSAEWOULDBLOCK == err ;
1277
+ #else
1278
+ if (EINTR == err )
1279
+ continue ;
1280
+ return_success = EWOULDBLOCK == err || EAGAIN == err ;
1281
+ #endif
1282
+ if (!return_success )
1283
+ return CURLM_WAKEUP_FAILURE ;
1284
+ }
1285
+ return CURLM_OK ;
1286
+ }
1287
+ }
1288
+ #endif
1289
+ return CURLM_WAKEUP_FAILURE ;
1187
1290
}
1188
1291
1189
1292
/*
@@ -2309,6 +2412,11 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
2309
2412
2310
2413
Curl_hash_destroy (& multi -> hostcache );
2311
2414
Curl_psl_destroy (& multi -> psl );
2415
+
2416
+ #ifdef ENABLE_WAKEUP
2417
+ sclose (multi -> wakeup_pair [0 ]);
2418
+ sclose (multi -> wakeup_pair [1 ]);
2419
+ #endif
2312
2420
free (multi );
2313
2421
2314
2422
return CURLM_OK ;
0 commit comments