Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP sem_get function fails

I have implemented an access control for insertions into a database table that is used for a reservation service. It works fine for some time, then the sem_get() function fails despite the fact that I call sem_release() after every sem_get().

case 'room':
    $key = "room";
    $semaphore = sem_get($key, 1, 0666, 1);
    if ($semaphore) {
        sem_acquire($semaphore);
        //do some stuff
        if ($already_reserved_rooms < $max_rooms) {
            $return="ok";
            sem_release($semaphore);
            return $return;
        }
          sem_release($semaphore);
    }
    else {
      //send me mail that semaphore failed 
    }

    return 'no rooms';
    break;

Should I call sem_remove() as well?

I followed steps on this site.

like image 1000
JokerDev Avatar asked Nov 03 '16 11:11

JokerDev


People also ask

Where does SEM_get() function come from?

The sem_get () function is provided by the Semaphore, Shared Memory and IPC component. This extension is not available on Windows platforms. Thanks for contributing an answer to Stack Overflow!

How do I access a semaphore created outside of PHP?

When using sem_get() to access a semaphore created outside PHP, note that the semaphore must have been created as a set of 3 semaphores (for example, by specifying 3 as the nsems parameter when calling the C semget() function), otherwise PHP will be unable to access the semaphore.

What happens when you call SEM_get() twice for the same key?

A second call to sem_get () for the same key will return a different semaphore identifier, but both identifiers access the same underlying semaphore. If key is 0, a new private semaphore is created for each call to sem_get () .


3 Answers

the sem_get function returns false in your case, because you give a string instead of integer.

Replace

$semaphore = sem_get($key, 1, 0666, 1);

by

$semaphore = sem_get(crc32($key), 1, 0666, 1);

It will work

like image 38
Arno Avatar answered Oct 11 '22 03:10

Arno


Removing Semaphores

Yes, you should call sem_remove() when you are done with the semaphore set. Otherwise, the semaphore set will persist in the system until you remove it. However, the fact that the semaphore set persists causes no problem while the number of semaphores is less than the SEMMNS limit:

SEMMNS System-wide limit on the number of semaphores: policy dependent (on Linux, this limit can be read and modified via the second field of /proc/sys/kernel/sem).

sem_remove() immediately removes the semaphore set awakening all processes blocked using this semaphore.

By the way, you can use the ipcrm command to remove semaphores from command line, and the ipcs command to show information on IPC facilities (including semaphores).

Releasing Semaphores

You are not required to call sem_release() while the auto-release flag (sem_get's 4th parameter) is on. But it is a good idea to release semaphores as long as you don't need the acquired "lock".

sem_release() only increments the value of internal semaphore. Think of it as an unlocking operation, the opposite of sem_acquire().

sem_get() Failures

The sem_get() function returns FALSE in the following cases

  • PHP parameter parsing failure (E_ERROR);
  • semaphore exists, but the calling process does not have permission to access the set (E_WARNING);
  • memory allocation error (E_WARNING);
  • the maximum number of semaphore sets, or the system wide maximum number of semaphores exceeds (E_WARNING)

In each of the cases sem_get logs an error, or a warning. So you have to check the logs in order to find out the root of the problem.

Since your code works for some time, it is not parameter parsing issue, and not the permissions. Memory allocation issues are rare. So it is very likely that you are running out of the semaphore number limits. Check out the man page for semget for reference. The man page describes how to read and modify the limits via /proc/sys/kernel/sem.

Refer to this answer for more information regarding the sysvsem extension internals.

like image 191
Ruslan Osmanov Avatar answered Oct 11 '22 05:10

Ruslan Osmanov


The $key argument for sem_get() is integer, while you are passing it as string. Please consider getting the integer key by the ftok() call.

So please consider replacing

$key = "room";

to the following code:

$project = "r"; // Project identifier. This must be a one character string.
$key = ftok(__FILE__, $project);
like image 1
Maxim Masiutin Avatar answered Oct 11 '22 03:10

Maxim Masiutin