Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Nov 2007 14:17:24 -0800
From:      Alfred Perlstein <alfred@freebsd.org>
To:        "M. Warner Losh" <imp@bsdimp.com>
Cc:        arch@FreeBSD.org
Subject:   Re: Code review request: small optimization to localtime.c
Message-ID:  <20071128221724.GS71382@elvis.mu.org>
In-Reply-To: <20071128.151021.709401576.imp@bsdimp.com>
References:  <20071128.151021.709401576.imp@bsdimp.com>

next in thread | previous in thread | raw e-mail | index | archive | help
See pthread_once...

Without pthread_once this is how it's suggested you do things
by just about every threading/smp book out there.

One thing you have to do is to make sure not to set "is_set"
until after the work is done.  Just use pthread_once.

-Alfred

* M. Warner Losh <imp@bsdimp.com> [071128 14:11] wrote:
> Please find enclosed some small optimizations.  I know they make a
> couple lines too long, I'll correct that before I commit.  They make
> the time functions do less redundant locking.
> 
> However, in many places we do the following:
> 
> 	pthread_mutex_lock();
> 	if (!is_set) {
> 		is_set = true;
> 		// do something
> 	}
> 	pthread_mutex_unlock();
> 
> This is wasteful.  We get locks ALL the time for every time operation,
> when in fact we need it more rarely.  If we can tolerate losing a
> race, we can eliminate the locking in all but the startup case and
> those threads racing the startup:
> 
> 	if (!is_set) {
> 		pthread_mutex_lock();
> 		if (!is_set) {
> 			is_set = true;
> 			// do something
> 		}
> 		pthread_mutex_unlock();
> 	}
> 
> here, we know that is_set only ever changes from false to true.  If it
> is already true, there's nothing to do.  If it is false, we may need
> to do something, so we lock, check to see if we really need to do it,
> etc.
> 
> Can anybody see a flaw in this logic?
> 
> Warner
> 
> Index: localtime.c
> ===================================================================
> RCS file: /cache/ncvs/src/lib/libc/stdtime/localtime.c,v
> retrieving revision 1.41
> diff -u -r1.41 localtime.c
> --- localtime.c	19 Jan 2007 01:16:35 -0000	1.41
> +++ localtime.c	28 Nov 2007 21:59:59 -0000
> @@ -1093,14 +1093,16 @@
>  	struct tm *p_tm;
>  
>  	if (__isthreaded != 0) {
> -		_pthread_mutex_lock(&localtime_mutex);
>  		if (localtime_key < 0) {
> -			if (_pthread_key_create(&localtime_key, free) < 0) {
> -				_pthread_mutex_unlock(&localtime_mutex);
> -				return(NULL);
> +			_pthread_mutex_lock(&localtime_mutex);
> +			if (localtime_key < 0) {
> +				if (_pthread_key_create(&localtime_key, free) < 0) {
> +					_pthread_mutex_unlock(&localtime_mutex);
> +					return(NULL);
> +				}
>  			}
> +			_pthread_mutex_unlock(&localtime_mutex);
>  		}
> -		_pthread_mutex_unlock(&localtime_mutex);
>  		p_tm = _pthread_getspecific(localtime_key);
>  		if (p_tm == NULL) {
>  			if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
> @@ -1146,16 +1148,18 @@
>  const long		offset;
>  struct tm * const	tmp;
>  {
> -	_MUTEX_LOCK(&gmt_mutex);
>  	if (!gmt_is_set) {
> -		gmt_is_set = TRUE;
> +		_MUTEX_LOCK(&gmt_mutex);
> +		if (!gmt_is_set) {
> +			gmt_is_set = TRUE;
>  #ifdef ALL_STATE
> -		gmtptr = (struct state *) malloc(sizeof *gmtptr);
> -		if (gmtptr != NULL)
> +			gmtptr = (struct state *) malloc(sizeof *gmtptr);
> +			if (gmtptr != NULL)
>  #endif /* defined ALL_STATE */
> -			gmtload(gmtptr);
> +				gmtload(gmtptr);
> +		}
> +		_MUTEX_UNLOCK(&gmt_mutex);
>  	}
> -	_MUTEX_UNLOCK(&gmt_mutex);
>  	timesub(timep, offset, gmtptr, tmp);
>  #ifdef TM_ZONE
>  	/*
> @@ -1187,14 +1191,16 @@
>  	struct tm *p_tm;
>  
>  	if (__isthreaded != 0) {
> -		_pthread_mutex_lock(&gmtime_mutex);
>  		if (gmtime_key < 0) {
> -			if (_pthread_key_create(&gmtime_key, free) < 0) {
> -				_pthread_mutex_unlock(&gmtime_mutex);
> -				return(NULL);
> +			_pthread_mutex_lock(&gmtime_mutex);
> +			if (gmtime_key < 0) {
> +				if (_pthread_key_create(&gmtime_key, free) < 0) {
> +					_pthread_mutex_unlock(&gmtime_mutex);
> +					return(NULL);
> +				}
>  			}
> +			_pthread_mutex_unlock(&gmtime_mutex);
>  		}
> -		_pthread_mutex_unlock(&gmtime_mutex);
>  		/*
>  		 * Changed to follow POSIX.1 threads standard, which
>  		 * is what BSD currently has.
> _______________________________________________
> freebsd-arch@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-arch
> To unsubscribe, send any mail to "freebsd-arch-unsubscribe@freebsd.org"

-- 
- Alfred Perlstein



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20071128221724.GS71382>