From: john on
Hi,

I have two processes running - one process created a semaphore whilst
the other just needs to look at it and perform an operation based on it
being set. Here is a rough copy of the code:


Process 1:

semget(key, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR|S_IROTH|S_IWOTH)
semctl(m_nSemID, 0, SETALL, arg)

struct sembuf stSemBuf[1];
stSemBuf[0].sem_num = 0;
stSemBuf[0].sem_op = 1;

while(bLoop)
{

if(semop(m_nSemID, stSemBuf, 1)!=0)
{
.....error
}

}


Process 2:

struct sembuf stSemBuf[1];
stSemBuf[0].sem_num = 0;
stSemBuf[0].sem_op = -1;

while(bLoop)
{
if(semop(nSemKey, stSemBuf, 1)==0)
{
...do something
}
}

Everything seems to run fine for about 5 minutes then I get errors in
process 1 semop with ERANGE. I had a read of the man pages but can't
figure out why I would get this error as I am not setting the SEM_UNDO flag.

Can anyway provide any insight into my problem or point me in the right
direction to sorting it out myself?

Cheers,

John.
From: Ersek, Laszlo on
On Tue, 13 Apr 2010, john wrote:

> I have two processes running - one process created a semaphore whilst
> the other just needs to look at it and perform an operation based on it
> being set. Here is a rough copy of the code:
>
> [...]
>
> Everything seems to run fine for about 5 minutes then I get errors in
> process 1 semop with ERANGE. I had a read of the man pages but can't
> figure out why I would get this error as I am not setting the SEM_UNDO
> flag.

Am I right to say that you race one process against another, the first
incrementing the semaphore value in a tight loop, the second decrementing
it? If so, and the first (the incrementing one) is for whatever reason
faster, then the semaphore value keeps increasing in the long term, and
then

http://www.opengroup.org/onlinepubs/9699919799/functions/semop.html

[ERANGE]
An operation would cause a semval to overflow the system-imposed limit,
or an operation would cause a semadj value to overflow the
system-imposed limit.

The most recent Linux manual page on semop()
<http://www.kernel.org/doc/man-pages/online/pages/man2/semop.2.html> says,

ERANGE For some operation sem_op+semval is greater than SEMVMX, the
implementation dependent maximum value for semval.

Even if there is no "strict" system-imposed limit,
<http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_sem.h.html>
says:

----v----
A semaphore shall be represented by an anonymous structure, which shall
include the following members:

unsigned short semval Semaphore value.
----^----

Thus USHRT_MAX is a natural limit.

lacos
From: john on
Ersek, Laszlo wrote:
> On Tue, 13 Apr 2010, john wrote:
>
>> I have two processes running - one process created a semaphore whilst
>> the other just needs to look at it and perform an operation based on
>> it being set. Here is a rough copy of the code:
>>
>> [...]
>>
>> Everything seems to run fine for about 5 minutes then I get errors in
>> process 1 semop with ERANGE. I had a read of the man pages but can't
>> figure out why I would get this error as I am not setting the SEM_UNDO
>> flag.
>
> Am I right to say that you race one process against another, the first
> incrementing the semaphore value in a tight loop, the second
> decrementing it? If so, and the first (the incrementing one) is for
> whatever reason faster, then the semaphore value keeps increasing in the
> long term, and then
>

I guess there is a race condition yes. I put a counter in and the first
process hits about ~47000 and the second process hits ~14000 when the
error occurs. I think my understanding of semaphores must be wrong - I
didn't realize that I had a incrementing semaphore. I was meaning to
create a binary semaphore i.e. only use it to keep the second process
informed that something has happened. I don't want to consume every
single semaphore that is set and that is why I thought a binary
semaphore would be ok.

Can you suggest a solution to my problem where I need one process to
tell another that something has happened e.g. event?

Regards,

John.
From: David Schwartz on
On Apr 14, 7:04 am, john <j...(a)replyatnewsgroup.com> wrote:

> Can you suggest a solution to my problem where I need one process to
> tell another that something has happened e.g. event?

Can you be more precise? Do you only have one event? Or do you want
the second process to be able to wait until the status of something
has changed?

The obvious answer is to use a process-shared mutex and a process-
shared condition variable with a predicate variable in shared memory
as well.

DS
From: Ersek, Laszlo on
On Wed, 14 Apr 2010, john wrote:

> Ersek, Laszlo wrote:
>>
>> Am I right to say that you race one process against another, the first
>> incrementing the semaphore value in a tight loop, the second
>> decrementing it? If so, and the first (the incrementing one) is for
>> whatever reason faster, then the semaphore value keeps increasing in
>> the long term, and then
>>
>
> I guess there is a race condition yes. I put a counter in and the first
> process hits about ~47000 and the second process hits ~14000 when the
> error occurs.

The system-imposed limit on the value of the conceptual semval member
seems to be 32767, then. (32767 ~= 47000 - 14000.)


> I think my understanding of semaphores must be wrong - I didn't realize
> that I had a incrementing semaphore. I was meaning to create a binary
> semaphore i.e. only use it to keep the second process informed that
> something has happened. I don't want to consume every single semaphore
> that is set and that is why I thought a binary semaphore would be ok.

After posting my followup, I also changed my mind a bit: your processes
probably didn't spin in tight loops, they rather were a heavy-weight
producer and a heavy-weight consumer, and the producer worked faster. I
thought the semaphore was okay for representing the current length of the
work queue, but then it was a strongly bounded one, at the very most
holding USHRT_MAX jobs. I considered suggesting another semaphore for
representing the empty slots in the queue, so that you can block on a full
queue in the producer, not only on an empty queue in the consumer.


> Can you suggest a solution to my problem where I need one process to
> tell another that something has happened e.g. event?

Which SUS version are you coding for? Starting with v2, you could use
process-shared POSIX threads mutexes and condition variables. If you're
coding for SUSv1, you could send non-queued signals (I'm too lazy to check
now if SUSv1 supports queued signals at all), eg. SIGUSR1. I assume your
consumer is already written to process all outstanding events when a
single notification (of some kind) is delivered, because you seem to have
supposed from the start that pending notifications coalesce.

Functions to use in the producer: kill(). Functions to use in the
consumer: sigemptyset(), sigaddset(), sigprocmask(), sigaction(),
sigsuspend(). I'll assume the consumer is single-threaded, you don't
fiddle with signal actions and masks otherwise, and whenever you wait for
the notification, you wait for nothing else.

#define _XOPEN_SOURCE /* SUSv1 */

#include <assert.h> /* assert() */
#include <signal.h> /* sigaction() etc */
#include <errno.h> /* errno */


static sigset_t usr1_unblk;


static void
usr1_handle(int sig)
{
assert(SIGUSR1 == sig);
}


static void
usr1_setup(void)
{
int ret;
struct sigaction sa;

/* reuse sa_mask for sigprocmask(); it won't hurt sigaction() either */
ret = sigemptyset(&sa.sa_mask); assert(0 == ret);
ret = sigaddset(&sa.sa_mask, SIGUSR1); assert(0 == ret);
ret = sigprocmask(SIG_BLOCK, &sa.sa_mask, &usr1_unblk); assert(0 == ret);

sa.sa_handler = &usr1_handle;
sa.sa_flags = 0;
ret = sigaction(SIGUSR1, &sa, 0); assert(0 == ret);
}


static void
usr1_wait(void)
{
int ret;

ret = sigsuspend(&usr1_unblk);
assert(-1 == ret && EINTR == errno);
}


Cheers,
lacos