1.8 Fix

The fix is 2 fold. First, we need to prevent the client from blocking. Then, we need the client to correctly implement the hide absolute option so that working it can properly process upload requests.

1.8.1 Prevent blocking

Since we are having problems with semaphores blocking ALL threads. We could tell them not to block then write them as a busy wait construct with a small time interval between retries.

Investigating src/sema.c source code, the only blocking calls are semop(2) with -1 as operation parameters. Consequently, we will both add IPC_NOWAIT to flag parameters in all of those and rewrite them as busy wait constructs.

Nevertheless, this does not solve the contention problem. Semaphores are built for protection of a shared resource; thus, we should add a thread appropriate mutual exclusion mechanism. The most appropriate seems to be mutexes.

Also, whenever we busy wait, we will call

void pthread_yield(void);

from pthread(3), increasing the chance that a concurrent thread releases the semaphore before our next try.

See the example Example 1-1

Example 1-1. Replacing a blocking semaphore operation with a non-blocking busy wait one

Replace

        void get_slice(int semid, SPD_SEMA semnum)
      2 {
                while(1)   
      4         {
                        struct sembuf local={0,-1,0};           /* slave sema */
      6 
                        local.sem_num=semnum;
      8                 if(semop(semid,&local,1)==0)
                        {   
     10                         /* we have what we want */
                                return;
     12                 }
                }
     14 }
          

with hopefully portable

        #include <sys/param.h>
      2 
        /* interval between busy wait tries measured in microseconds */
      4 #define MUTEX_BUSY_WAIT_TIME    5000
        
      6 void get_slice(int semid, SPD_SEMA semnum)
        {
      8 #if !(defined(BSD) && (BSD >= 199103))
                struct sembuf local={0,-1,0};                                   /* slave sema */
     10 #else
                struct sembuf local={0,-1,0|IPC_NOWAIT};                        /* slave sema */(1)
     12 #endif
                local.sem_num=semnum;
     14 
                (void) lp_mutex_lock_(semaphore_mutex);            (2)
     16         while(1)
                {
     18                 switch (semop(semid,&local,1)) {
                                case 0: (void) lp_mutex_unlock_(semaphore_mutex);(3)
     20                                                 /* we have what we want */
                                                        return;
     22                                                 break;
                                case -1:        switch(errno) {    (4)
     24                                                 case EAGAIN:                    /* triggers busy wait */
                                                        case EINTR:                     /* interrupted by system call, try again */
     26                                                                         pthread_yield();(5)
                                                                                usleep(MUTEX_BUSY_WAIT_TIME);   /* busy wait with a small time out */(6)
     28                                                                         continue;
                                                                                break;
     30                                         }
                        }
     32         }
        }
     34     
(1)
Have a non-blocking semaphore
(2)
Add a mutex protection around the shared semaphore. Acquire mutex lock before trying semaphore
(3)
Add a mutex protection around the shared semaphore. Release mutex lock when we are done with the semaphore
(4)
If both the semaphore fails AND it signals that it would have blocked if it could, we will have to try the semaphore again
(5)
Before trying again, we yield the processor by letting another thread run. Another thread might release the required semaphore
(6)
To avoid hogging the processor with multiple retries, we will wait a time interval before retrying

1.8.1.1 Fix

  1. Copy my lp_mutex.c BSD licensed mutex handling routines to subdirectory src

  2. Apply patch patch-configure.in against configure.in to enable detection of header file sys/param.h which is used to detect if current system is BSD based

  3. Apply patch patch-src::Makefile.am against src/Makefile.am to connect lp_mutex.c to the build

  4. Apply patch patch-src::sema.c against src/sema.c hopefully adding more portability to the semaphore code

1.8.2 Correct hide absolute option

First, we need to pass the correct upload requests to

int file_in_db(char *filename, int *virtual);

routine that checks if the files exist. Then, we have to make sure that this checking routine understands the requests.

We will move the hide absolute option handling routines before the check routine. Then, we will add a specific handling to the check routine.

1.8.2.1 Fix

  1. Apply patch patch-src::dc_manage.c against src/dc_manage.c so that the checking routine receives a correct file request

  2. Apply patch patch-src::mydb.c against src/mydb.c so that the checking routine understands the file requested

For questions about FreeBSD, read the <documentation>.

For questions about the FreeBSD ports system, e-mail <ports@FreeBSD.org>.
For questions about this documentation, e-mail <lioux@FreeBSD.org>.