Return-Path: X-Original-To: apmail-httpd-modules-dev-archive@minotaur.apache.org Delivered-To: apmail-httpd-modules-dev-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id D3F57D6DD for ; Mon, 10 Sep 2012 12:46:43 +0000 (UTC) Received: (qmail 37480 invoked by uid 500); 10 Sep 2012 12:46:43 -0000 Delivered-To: apmail-httpd-modules-dev-archive@httpd.apache.org Received: (qmail 37331 invoked by uid 500); 10 Sep 2012 12:46:43 -0000 Mailing-List: contact modules-dev-help@httpd.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: modules-dev@httpd.apache.org Delivered-To: mailing list modules-dev@httpd.apache.org Received: (qmail 37313 invoked by uid 99); 10 Sep 2012 12:46:43 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 10 Sep 2012 12:46:43 +0000 X-ASF-Spam-Status: No, hits=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of info@bnoordhuis.nl designates 209.85.160.45 as permitted sender) Received: from [209.85.160.45] (HELO mail-pb0-f45.google.com) (209.85.160.45) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 10 Sep 2012 12:46:36 +0000 Received: by pbbrp12 with SMTP id rp12so1266723pbb.18 for ; Mon, 10 Sep 2012 05:46:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-originating-ip:in-reply-to:references:date :message-id:subject:from:to:content-type:x-gm-message-state; bh=RAWQzbuLwrZUJj/F6UZEAExtSr+ydhLwGkqtf8YkE+w=; b=PaScJ/ON2w2VWuyqu7Red97J5uGwv+7TY5d9X/J+4kvcTHij3V2CJ+lhFzPdtv/0QU OGisQHNoptip8m4+ELfEq5mBNKl4/zgE/zwt/Elu15OeIcTf4p1FaYCPf/r7BnOAtmzW tzVh1Id2hR6LhEgzVVjfJl7x+mJ6LJW/UpP2gdaTDmEqGlHZOWwyMy0yZCUAjXKWT+AF pR66SfLq2+vjsadJWArajw77HWqxktW0P61P3vnHA+0odNuz2v+6E/d52pfVvFf6NVHs iuKZGX3ErEEYkP+3ilChwN737ZaNB7DaVztTCwFVn8IXlpBiNC2WGNZt5BiAUT0kGmSm ghtg== MIME-Version: 1.0 Received: by 10.68.130.201 with SMTP id og9mr5951105pbb.12.1347281175184; Mon, 10 Sep 2012 05:46:15 -0700 (PDT) Received: by 10.68.25.199 with HTTP; Mon, 10 Sep 2012 05:46:15 -0700 (PDT) X-Originating-IP: [87.214.96.125] In-Reply-To: <8B2FC4EBE135700A0FE1337D@Ximines.local> References: <36D882E966A33CA59AFDA4DB@Ximines.local> <8B2FC4EBE135700A0FE1337D@Ximines.local> Date: Mon, 10 Sep 2012 14:46:15 +0200 Message-ID: Subject: Re: Bucket brigade & filter thread safety From: Ben Noordhuis To: modules-dev@httpd.apache.org, Alex Bligh Content-Type: text/plain; charset=ISO-8859-1 X-Gm-Message-State: ALoCoQmfBUWOrpRLE9TWd48eIAXCXDeshR+tmjRLUVbbXTRyzdYEsx8KCGflSXkkt9EJRcX41KCR X-Virus-Checked: Checked by ClamAV on apache.org On Mon, Sep 10, 2012 at 10:47 AM, Alex Bligh wrote: > Ben, > > Thanks for your reply. > > >>> I am suffering from very occasional corruption of the bucket brigade >>> which normally shows up as a corrupted pool pointer or a bogus bucket >>> entry in thread #1 (for instance a SEGV in apr_brigade_length). >>> Interestingly this is the relatively quiet input brigade which is only >>> ever touched by the main apache thread. It's almost as if an allocator >>> is not thread safe. >> >> >> That's because it isn't unless you explicitly make it so (which no MPM >> does). > > > What I'm trying to do is to use a separate allocator per thread. > > >>> However, I'm using a separate bucket allocator (see code above) and (at >>> least in my code) a separate pool. >> >> >> They're not really separate, the sub pool is created off r->pool. You >> should probably use apr_pool_create_ex() here with parent=NULL and an >> allocator that you created with apr_allocator_create() + >> apr_allocator_mutex_set(). > > > OK I based this on the docs for apr_pool_create which says at > http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#ga918adf3026c894efeae254a0446aed3b > > : This function is thread-safe, in the sense that multiple threads can > : safely create subpools of the same parent pool concurrently. Similarly, a > : subpool can be created by one thread at the same time that another thread > : accesses the parent pool. > > Have I understood that wrong? No, but the documentation omits some crucial details. apr_pool_create() is thread-safe only if: 1. libapr is compiled with APR_HAS_THREADS 2. APR_POOL_DEBUG is turned off 3. the parent pool has a thread-safe allocator (which is true for the global allocator that is used when parent=NULL, provided conditions #1 and #2 are satisfied) The pools you get from httpd core satisfy #3 but a module may replace e.g. r->pool with another pool that doesn't. Ergo, don't rely on a pool being thread safe unless you explicitly make it so. >> That won't solve all your problems though. Bucket brigades are not >> thread safe, you will need something to synchronize on. > > > So what I was trying to do was to use > a) the input bucket brigade in thread #1 (main thread) > b) the output bucket brigade in thread #2 > in an attempt to avoid synchronization > > But what I don't understand is whether thread #2, in writing > to the output filters (which presumably have a reference > to r->pool) will need synchronisation. Yes. It's not just because r->pool may or may not be synchronized, the internal structure of the bucket brigade is not protected by any locks either. > And if I have to synchronize, how do I do that in practice? > Thread #2 does and ap_fwrite/ap_flush so I can hold a mutex > there. But what do I do in thread #1, which calls ap_brigade_get > and blocks? I can't hold a mutex during that. I can make it > a non-blocking ap_brigade_get (if I understood how to do it) Non-blocking reads are pretty straightforward: apr_thread_mutex_lock(&mutex); rv = ap_get_brigade(f->next, bb, AP_MODE_READBYTES, APR_NONBLOCK_READ, len); if (APR_STATUS_IS_EAGAIN(rv)) apr_thread_cond_wait(&cond, &mutex); rv = ap_get_brigade(f->next, bb, AP_MODE_READBYTES, APR_NONBLOCK_READ, len); apr_thread_mutex_unlock(&mutex); The other thread wakes up this thread with apr_thread_cond_signal(&cond). > but what I really need is the equivalent of a select() which > I can do with the mutex not held (or some way to drop the mutex > during the raw reads). Any ideas? You could set up a pollset in the main thread and funnel incoming data into your bucket brigade. Not terribly efficient (lots of context switches) but the real world impact may very well be negligible and you can support multi-process setups with zero changes to your code.