187187#include "apr_lib.h"
188188#include "apr_hash.h"
189189#include "apr_optional.h"
190+ #include "apr_anylock.h"
190191
191192#define APR_WANT_STRFUNC
192193#include "apr_want.h"
199200#include "http_log.h"
200201#include "http_protocol.h"
201202#include "util_time.h"
203+ #include "ap_mpm.h"
202204
203205#if APR_HAVE_UNISTD_H
204206#include <unistd.h>
@@ -237,6 +239,7 @@ static ap_log_writer* ap_log_set_writer(ap_log_writer *handle);
237239static ap_log_writer * log_writer = ap_default_log_writer ;
238240static ap_log_writer_init * log_writer_init = ap_default_log_writer_init ;
239241static int buffered_logs = 0 ; /* default unbuffered */
242+ static apr_array_header_t * all_buffered_logs = NULL ;
240243
241244/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
242245 * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512
@@ -290,6 +293,7 @@ typedef struct {
290293 apr_file_t * handle ;
291294 apr_size_t outcnt ;
292295 char outbuf [LOG_BUFSIZE ];
296+ apr_anylock_t mutex ;
293297} buffered_log ;
294298
295299typedef struct {
@@ -1215,6 +1219,10 @@ static apr_status_t flush_all_logs(void *data)
12151219
12161220static int init_config_log (apr_pool_t * pc , apr_pool_t * p , apr_pool_t * pt , server_rec * s )
12171221{
1222+ if (buffered_logs ) {
1223+ all_buffered_logs = apr_array_make (p , 5 , sizeof (buffered_log * ));
1224+ }
1225+
12181226 /* First, do "physical" server, which gets default log fd and format
12191227 * for the virtual servers, if they don't override...
12201228 */
@@ -1231,9 +1239,41 @@ static int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server
12311239
12321240static void init_child (apr_pool_t * p , server_rec * s )
12331241{
1242+ int mpm_threads ;
1243+
1244+ ap_mpm_query (AP_MPMQ_MAX_THREADS , & mpm_threads );
1245+
12341246 /* Now register the last buffer flush with the cleanup engine */
12351247 if (buffered_logs ) {
1248+ int i ;
1249+ buffered_log * * array = (buffered_log * * )all_buffered_logs -> elts ;
1250+
12361251 apr_pool_cleanup_register (p , s , flush_all_logs , flush_all_logs );
1252+
1253+ for (i = 0 ; i < all_buffered_logs -> nelts ; i ++ ) {
1254+ buffered_log * this = array [i ];
1255+
1256+ #if APR_HAS_THREADS
1257+ if (mpm_threads > 1 ) {
1258+ apr_status_t rv ;
1259+
1260+ this -> mutex .type = apr_anylock_threadmutex ;
1261+ rv = apr_thread_mutex_create (& this -> mutex .lock .tm ,
1262+ APR_THREAD_MUTEX_DEFAULT ,
1263+ p );
1264+ if (rv != APR_SUCCESS ) {
1265+ ap_log_error (APLOG_MARK , APLOG_CRIT , rv , s ,
1266+ "could not initialize buffered log mutex, "
1267+ "transfer log may become corrupted" );
1268+ this -> mutex .type = apr_anylock_none ;
1269+ }
1270+ }
1271+ else
1272+ #endif
1273+ {
1274+ this -> mutex .type = apr_anylock_none ;
1275+ }
1276+ }
12371277 }
12381278}
12391279
@@ -1321,12 +1361,13 @@ static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
13211361 const char * name )
13221362{
13231363 buffered_log * b ;
1324- b = apr_palloc (p , sizeof (buffered_log ));
1364+ b = apr_pcalloc (p , sizeof (buffered_log ));
13251365 b -> handle = ap_default_log_writer_init (p , s , name );
1326- b -> outcnt = 0 ;
13271366
1328- if (b -> handle )
1367+ if (b -> handle ) {
1368+ * (buffered_log * * )apr_array_push (all_buffered_logs ) = b ;
13291369 return b ;
1370+ }
13301371 else
13311372 return NULL ;
13321373}
@@ -1344,6 +1385,9 @@ static apr_status_t ap_buffered_log_writer(request_rec *r,
13441385 apr_status_t rv ;
13451386 buffered_log * buf = (buffered_log * )handle ;
13461387
1388+ if ((rv = APR_ANYLOCK_LOCK (& buf -> mutex )) != APR_SUCCESS ) {
1389+ return rv ;
1390+ }
13471391
13481392 if (len + buf -> outcnt > LOG_BUFSIZE ) {
13491393 flush_log (buf );
@@ -1368,6 +1412,8 @@ static apr_status_t ap_buffered_log_writer(request_rec *r,
13681412 buf -> outcnt += len ;
13691413 rv = APR_SUCCESS ;
13701414 }
1415+
1416+ APR_ANYLOCK_UNLOCK (& buf -> mutex );
13711417 return rv ;
13721418}
13731419
0 commit comments