Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:1329 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 55002 invoked from network); 7 May 2003 02:40:24 -0000 Received: from unknown (HELO hotmail.com) (64.4.22.91) by pb1.pair.com with SMTP; 7 May 2003 02:40:24 -0000 Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC; Tue, 6 May 2003 19:40:24 -0700 Received: from 66.80.46.131 by law15-dav34.adinternal.hotmail.com with DAV; Wed, 07 May 2003 02:40:24 +0000 X-Originating-IP: [66.80.46.131] X-Originating-Email: [ed000001@hotmail.com] To: References: <20030506203232.K61894-100000@x-wing.brouda.com> Date: Tue, 6 May 2003 22:40:39 -0400 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 6.00.2800.1158 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165 Message-ID: X-OriginalArrivalTime: 07 May 2003 02:40:24.0247 (UTC) FILETIME=[02B74C70:01C31442] Subject: Re: [PHP-DEV] Thread Safety - test_and_set primitive included From: ed000001@hotmail.com ("Ed") Dear folks, Forgive me for barging in, but I'm using a snippet of code that might be of interest. It is a "test and set" function to be used for locking resources across threads. I was looking at the TSRM implementation (including the Mutexes) and it did do quite what i needed -- things are not atomic. So here are a couple of primitives in VC++ (Windows) and gcc (Linux) for the i386 platform. The Linux piece was "stolen" from /usr/include/asm/bitops.h -- originally written by Linus Torvalds. I "ported" it to VC++. With these 2 inline primitives people developing extensions should be able to implement thread shared resources with safety -- provided one does not make mistakes ;-) They seem to work -- no guarantees though :-) There is an example of usage below, but one can come up a number of variations for the "wrappers" based on the "inlines". Thanks for the great tool! All the best, Ed Hoo ed000001@hotmail.com *** MY_FILE.H *** /* ------------------------------------------------------- *\ * Primitives for a simple mutex implementation * ------------------------------------------------------- */ #define ADDR (*(volatile long *) addr) #ifdef WIN32 static __forceinline int test_and_set(int nr, volatile void *addr) { __asm { mov eax, nr mov ebx, addr lock bts [ebx], eax sbb eax, eax } /* Return with result in EAX */ } static __forceinline int test_and_clear(int nr, volatile void *addr) { __asm { mov eax, nr mov ebx, addr lock btr [ebx], eax sbb eax, eax } /* Return with result in EAX */ } #else static __inline__ int test_and_set(int nr, volatile void *addr) { int oldbit; __asm__ __volatile__( "lock ; " "btsl %2,%1\n\tsbbl %0,%0" :"=r" (oldbit),"=m" (ADDR) :"Ir" (nr) : "memory"); return oldbit; } static __inline__ int test_and_clear(int nr, volatile void *addr) { int oldbit; __asm__ __volatile__( "lock ; " "btrl %2,%1\n\tsbbl %0,%0" :"=r" (oldbit),"=m" (ADDR) :"Ir" (nr) : "memory"); return oldbit; } #endif *** MY_FILE.C *** /* ------------------------------------------------------- *\ * mutex_lock(int resource_id) * * Waits until resource is avaliable, locks it and then returns * ------------------------------------------------------- */ void mutex_lock(int n_resource_id) { if ( n_resource_id < 0 || n_resource_id > 31 ) return; while ( test_and_set(n_resource_id, &ng_mutex) ) Sleep(1); } /* ------------------------------------------------------- *\ * mutex_unlock(int resource_id) * * Unlocks a resource, we assumed it's been called by the resource "locker" * ------------------------------------------------------- */ void mutex_unlock(int n_resource_id) { if ( n_resource_id < 0 || n_resource_id > 31 ) return; test_and_clear(n_resource_id, &ng_mutex); } /* ------------------------------------------------------- *\ * Mutexes -- up to 32 "mutexes" in ng_mutex [0..31] * ------------------------------------------------------- */ static unsigned int ng_mutex = 0; #define MUTEX_FIELD_HASH 0 /* ------------------------------------------------------- *\ * Variables needing thread safety * ------------------------------------------------------- */ static t_field_hash* pg_field_hash = NULL; static int pg_field_hash_references = 0; /* ------------------------------------------------------- *\ * PHP_MINIT_FUNCTION * ------------------------------------------------------- */ PHP_MINIT_FUNCTION(dvdaf) { mutex_lock(MUTEX_FIELD_HASH); { if ( ! pg_field_hash ) { pg_field_hash = malloc(gp_field_count * sizeof(t_field_hash)); pg_field_hash_references = 1; // calculate hash } else { pg_field_hash_references++; } } mutex_unlock(MUTEX_FIELD_HASH); return SUCCESS; } /* ------------------------------------------------------- *\ * PHP_MSHUTDOWN_FUNCTION * ------------------------------------------------------- */ PHP_MSHUTDOWN_FUNCTION(dvdaf) { mutex_lock(MUTEX_FIELD_HASH); { if ( --pg_field_hash_references <= 0 ) { free(pg_field_hash); pg_field_hash = NULL; pg_field_hash_references = 0; } } mutex_unlock(MUTEX_FIELD_HASH); return SUCCESS; }