Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Sun, 1 Mar 2015 21:24:09 +0300 (MSK)
From: Alexander Monakov <amonakov@...ras.ru>
To: musl@...ts.openwall.com
Subject: Re: semaphore redesign



On Sun, 1 Mar 2015, Szabolcs Nagy wrote:

> * Alexander Monakov <amonakov@...ras.ru> [2015-02-28 02:21:22 +0300]:
> > int sem_post(sem_t *sem)
> > {
> > 	int val;
> > 	do {
> > 		val = sem->__val[0];
> > 		if (val == SEM_VALUE_MAX) {
> > 			errno = EOVERFLOW;
> > 			return -1;
> 
> as discussed on irc early return here without a barrier is not ok
> (it is a hard to observe corner case, i add the comment here so
> it does not get forgotten)

We further discussed that to fix it, one can recheck the value after a barrier
in the error path, and restart from the beginning if it changed, or always
proceed to CAS (with value changed only if not leading to error), and handle
errors after the cas-retry loop.  The following code implements the latter
approach.  I strongly prefer it for sem_trywait, where I think EAGAIN is
relatively common.  For sem_post it's not so clear cut for me, as EOVERFLOW
should be extremely rare, but still it helps to get good code layout from the
compiler (otherwise GCC lays out error return path inside of the cas loop).

int sem_trywait(sem_t *sem)
{
	int val;
	do val = sem->__val[0];
	while (val != a_cas(sem->__val, val, val-!!(val>0)));
	if (val > 0) return 0;
	errno = EAGAIN;
	return -1;
}

int sem_post(sem_t *sem)
{
	int val;
	do val = sem->__val[0];
	while (val != a_cas(sem->__val, val, val+!!(val<SEM_VALUE_MAX)));
	if (val < 0) {
		int priv = sem->__val[2];
		a_inc(sem->__val+1);
		__wake(sem->__val+1, 1, priv);
	}
	if (val < SEM_VALUE_MAX) return 0;
	errno = EOVERFLOW;
	return -1;
}

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.