Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Dec 2007 23:59:29 +0100
From:      Karsten Behrmann <BearPerson@gmx.net>
To:        freebsd-arch@freebsd.org
Subject:   Re: Code review request: small optimization to localtime.c
Message-ID:  <20071203235929.685d3674@Karsten.Behrmanns.Kasten>
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
--Sig_w9H.JONpwy2BbOTeikusyyT
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: quoted-printable

Hi there,

[ we do ]

> 	pthread_mutex_lock();
> 	if (!is_set) {
> 		is_set =3D true;
> 		// do something
> 	}
> 	pthread_mutex_unlock();

[couldn't we do]

> 	if (!is_set) {
> 		pthread_mutex_lock();
> 		if (!is_set) {
> 			is_set =3D true;
> 			// do something
> 		}
> 		pthread_mutex_unlock();
> 	}

Ah, the old "double-checked locking" thing. Take what I say here
with a grain of salt: I'm a plain programmer, not very versed in
different architectures, so I just pick up what I hear.

essentially, the problem with the scheme is that plain variable
writes may not be ordered as expected, making them unsuitable to
communicate between threads and processors, depending on compiler
and architecture.

Let's take the example

  pthread_mutex_lock();
  if (!is_set) {
    a =3D 3;
    b =3D 4;
    c =3D a * b;
    is_set =3D true;
  }
  pthread_mutex_unlock();

Now, an optimizing compiler might put a and b into registers,
compute a * b while storing a 1 to is_set, and then store a, b, and
c from registers into memory. As I said, I'm not actually sure
where compilers are allowed to do this.

Also, on some architectures, the caching structure may cause writes
to is_set to show up earlier on another CPU than writes to other
parts of memory, if you're unlucky.

So the bottom line is, in some situations, writes to memory don't
neccessarily take effect everywhere in the same order as the code
would suggest, breaking double-checked locking. is_set could end
up getting set before the "something" part has been executed.
You need the synchronization to ensure consistency of data before
being sure your checks do what you think they do.

In fact, in your patch, you sometimes actually set the variable
getting checked before setting the data it is supposed to protect ;-)

> -	_MUTEX_LOCK(&gmt_mutex);
>  	if (!gmt_is_set) {
> -		gmt_is_set =3D TRUE;
> +		_MUTEX_LOCK(&gmt_mutex);
> +		if (!gmt_is_set) {
> +			gmt_is_set =3D TRUE;

XXX - at this point, gmt_is_set is TRUE but gmtptr is not initialized yet.

>  #ifdef ALL_STATE
> -		gmtptr =3D (struct state *) malloc(sizeof *gmtptr);
> -		if (gmtptr !=3D NULL)
> +			gmtptr =3D (struct state *) malloc(sizeof *gmtptr);
> +			if (gmtptr !=3D NULL)
>  #endif /* defined ALL_STATE */
> -			gmtload(gmtptr);
> +				gmtload(gmtptr);
> +		}
> +		_MUTEX_UNLOCK(&gmt_mutex);
 	}
-	_MUTEX_UNLOCK(&gmt_mutex);


So Far,
  Karsten Behrmann

--Sig_w9H.JONpwy2BbOTeikusyyT
Content-Type: application/pgp-signature; name=signature.asc
Content-Disposition: attachment; filename=signature.asc

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (GNU/Linux)

iD8DBQFHVIpVAksKLoO3vywRAj3gAKCTAcmVaXGGUiSa6feF1UveYDbhNACaA8B2
PMVBUfz8oM9Kjv+KHZ/bfxM=
=I8Wk
-----END PGP SIGNATURE-----

--Sig_w9H.JONpwy2BbOTeikusyyT--



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