5

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.

Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60
JokerDev
  • 151
  • 2
  • 15
  • 2
    When `sem_get` fails, it logs a warning. Show us the warning. – Ruslan Osmanov Nov 03 '16 at 11:40
  • I'd say from the description of `sem_remove` it's definitely not something you want to be doing before you're completely done with that semaphore in **all** processes. – apokryfos Nov 03 '16 at 11:47
  • thanks sir for reply ,this all what i can found PHP Warning: sem_release(): SysV semaphore 5 (key 0x214) is not currently acquired – JokerDev Nov 03 '16 at 11:48
  • 3
    Out of curiosity, why don't you just lock the database table instead of using a semaphore? – apokryfos Nov 03 '16 at 11:49
  • @apokryfos thanks for your comment , because there is a lot of cases in this table and i want to lock based on each one not on entire table . – JokerDev Nov 03 '16 at 12:00
  • @RuslanOsmanov please see my log above – JokerDev Nov 03 '16 at 12:10
  • @drupaler1, where? Have you updated the question? I don't see any logs here. – Ruslan Osmanov Nov 03 '16 at 14:43
  • @RuslanOsmanov it seem that it fails in step sem_get for no reason – JokerDev Nov 03 '16 at 15:17
  • @drupaler1, everything has a reason, and [`sem_get`](https://github.com/php/php-src/blob/16160386982a86e6ec7969c6c89707d38228f19e/ext/sysvsem/sysvsem.c#L189) logs a warning in case of failure. So please show the logs. – Ruslan Osmanov Nov 03 '16 at 15:33

3 Answers3

3

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.

Community
  • 1
  • 1
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60
  • thanks sir for your comment ,but what is the difference between it and sem_release? and then how i will control semaphore for other users as i want them all to share same semaphore. – JokerDev Nov 03 '16 at 12:03
  • when you are saying "when you are done " you mean at the end of the above case in my code , if i called sem_remove() at the end of the case will it effect the other processes that waiting for the one who currently acquiring the semaphore to release ? – JokerDev Nov 03 '16 at 12:24
  • @drupaler1, `sem_release` unlocks a semaphore, `sem_remove` removes a semaphore set. You can leave the semaphore set persistent, but it would be less error-prone to remove it somewhere near the request shutdown phase. By _done with a semaphore set_ I mean the point when you no longer need to perform any operations on the semaphore set. `sem_acquire` blocks until the semaphore can be acquired. As long as the semaphore set exists, you can acquire/release freely. You _are not required to remove_ the sem.set. See the updated answer. – Ruslan Osmanov Nov 03 '16 at 16:33
  • sorry for late reply ,but i have used ipcs and ipcrm and removed all the old semaphores ,and uploaded the new code again ,it works fine for about 20 hour and failed again to get semaphore . log now contains those two llines repeated : `sem_get(): failed for key 0x20e: No space left on device` `sem_remove() expects parameter 1 to be resource, boolean given` – JokerDev Nov 04 '16 at 12:23
  • @drupaler1, it's `ENOSPC` error, which means that the system limit for the maximum number of semaphore sets (`SEMMNI`), or the system wide maximum number of semaphores (`SEMMNS`) exceeded. `SEMMNI` is the 4th field of `/proc/sys/kernel/sem`, `SEMMNS` is the 2nd field. Check how many semaphores do you have with `ipcs` – Ruslan Osmanov Nov 04 '16 at 12:35
  • @drupaler1, obviously, you should reduce the number of different keys – Ruslan Osmanov Nov 04 '16 at 13:19
  • guess i will have 1200 different semaphore is that acceptable ? – JokerDev Nov 05 '16 at 21:02
  • @drupaler1, as I said, check your `/proc/sys/kernel/sem`. The 2nd field is system-wide limit on the number of semaphores, the 4th - system-wide limit on the number of semaphore sets. `sem_get` creates a set of 3 semaphores. – Ruslan Osmanov Nov 06 '16 at 02:34
2

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

Arno
  • 1,309
  • 14
  • 20
1

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);
Maxim Masiutin
  • 3,991
  • 4
  • 55
  • 72