Hi,

I just ran into a situtation where I didn't want sem_acquire() to block
forever if the semaphore was already locked, but instead just return an
error condition.  There didn't seem to be a way to do this in current PHP
API, so I wrote a patch for it.

I tried to write it in such a way that current scripts that use
sem_acquire() would not break.


The new sem_acquire signature is:
        int sem_acquire (int sem_identifier [, int nowait])


If the nowait flag is specified, sem_acquire() will return false
immediately if it is unable to acquire the semaphore without blocking.

When sem_acquire() returns false, the nowait flag will be true if the
semaphore could not be acquired without blocking.  The nowait flag will be
false if a "normal" sem_acquire() error occurred.

If sem_acquire() returns true, the value of nowait should be ignored.

The input value of nowait is ignored, and must be specified as a
reference.  If the nowait flag is not specified, the behaviour of
sem_acquire is identical to the current PHP behaviour.


PHP code sample
------------------------
$nowait = 0; /* initialize the variable */
$id = sem_get(0xF00);

sem_acquire($id); /* lock */

/* lock again */
if (!sem_acquire($id, &$nowait)) {
        if ($nowait) {
                echo "Already locked.";
        } else {
                die("sem_acquire error occurred");
        }
}

/* release the id */
sem_release($id);
------------------------


Below is the patch against PHP 4.0.4pl1.


Cheers,
Michael




--- php-4.0.4pl1.orig/ext/sysvsem/sysvsem.c     Wed Oct 25 13:44:01 2000
+++ php-4.0.4pl1/ext/sysvsem/sysvsem.c  Mon Jan 22 11:37:12 2001
@@ -283,8 +283,8 @@

 static void php_sysvsem_semop(INTERNAL_FUNCTION_PARAMETERS, int acquire)
 {
-       pval **arg_id;
-       int id, type;
+       pval **arg_id, **arg_nowait;
+       int id, type, nowait;
        sysvsem_sem *sem_ptr;
     struct sembuf sop;

@@ -295,7 +295,31 @@
                        }
                        convert_to_long_ex(arg_id);
                        id = (int)(*arg_id)->value.lval;
+                       nowait = 0;
                        break;
+
+               case 2:
+                       /* nowait flag is only allowed for sem_acquire */
+                       if (!acquire) {
+                         WRONG_PARAM_COUNT;
+                       }
+                       if (zend_get_parameters_ex(2, &arg_id, &arg_nowait)==FAILURE) {
+                         RETURN_FALSE;
+                       }
+
+                       if (!ParameterPassedByReference(ht, 2)) {
+                         php_error(E_WARNING, "nowait flag must be passed by 
+reference.");
+                         RETURN_FALSE;
+                       }
+
+                       convert_to_long_ex(arg_id);
+                       convert_to_boolean_ex(arg_nowait);
+
+                       id = (int)(*arg_id)->value.lval;
+                       nowait = 1;
+                       (int)(*arg_nowait)->value.lval = 0;
+                       break;
+
                default:
                        WRONG_PARAM_COUNT;
                        break;
@@ -315,13 +339,25 @@
     sop.sem_num = SYSVSEM_SEM;
     sop.sem_op  = acquire ? -1 : 1;
     sop.sem_flg = SEM_UNDO;
+    if (nowait) {
+                       sop.sem_flg |= IPC_NOWAIT;
+    }

     while (semop(sem_ptr->semid, &sop, 1) == -1) {
-               if (errno != EINTR) {
-                       php_error(E_WARNING, "semop(%s) failed for key 0x%x: %s",
-                                          acquire ? "acquire" : "release",  
sem_ptr->key, strerror(errno));
-                       RETURN_FALSE;
-               }
+                       switch (errno) {
+                       case EINTR:
+                         break;
+                       case EAGAIN:
+                         if (nowait) {
+                           (int)(*arg_nowait)->value.lval = 1;  /* set nowait flag */
+                           RETURN_FALSE;
+                         }
+                       /* fall through */
+                       default:
+                         php_error(E_WARNING, "semop(%s) failed for key 0x%x: %s",
+                           acquire ? "acquire" : "release",  sem_ptr->key, 
+strerror(errno));
+                         RETURN_FALSE;
+                       }
        }

        sem_ptr->count -= acquire ? -1 : 1;




--
Michael Vines
Black Echo Systems Inc.
[EMAIL PROTECTED]






-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]

Reply via email to