semaphore.c

Go to the documentation of this file.
00001 /*                     S E M A P H O R E . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup thread */
00023 /*@{*/
00024 /** @file semaphore.c
00025  *@brief semaphore implementation
00026  *
00027  *  Machine-specific routines for parallel processing.
00028  *  Primarily for handling semaphores for critical sections.
00029  *
00030  *  The new paradigm:  semaphores are referred to, not by a pointer,
00031  *  but by a small integer.  This module is now responsible for obtaining
00032  *  whatever storage is needed to implement each semaphore.
00033  *
00034  *  Note that these routines can't use bu_log() for error logging,
00035  *  because bu_log() accquires semaphore #0 (BU_SEM_SYSCALL).
00036  *
00037  *  For code conversion hints, see "h/compat4.h"
00038  *
00039  *  @author
00040  *      Michael John Muuss
00041  *
00042  *  @par Source -
00043  *      The U. S. Army Research Laboratory
00044  * @n   Aberdeen Proving Ground, Maryland  21005-5068  USA
00045  *
00046  */
00047 
00048 
00049 #ifndef lint
00050 static const char RCSsemaphore[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbu/semaphore.c,v 14.14 2006/09/03 15:14:07 lbutler Exp $ (ARL)";
00051 #endif
00052 
00053 #include "common.h"
00054 
00055 #include <stdlib.h>
00056 #include <stdio.h>
00057 #include <ctype.h>
00058 #include <math.h>
00059 #include "machine.h"
00060 #include "bu.h"
00061 
00062 #ifdef CRAY
00063 # include <sys/category.h>
00064 # include <sys/resource.h>
00065 # include <sys/types.h>
00066 # ifdef CRAY1
00067 #  include <sys/machd.h>        /* For HZ */
00068 # endif
00069 struct bu_semaphores {
00070         long    magic;
00071         long    p;
00072 };
00073 # define DEFINED_BU_SEMAPHORES  1
00074 #endif
00075 
00076 #ifdef CRAY2
00077 #undef MAXINT
00078 # include <sys/param.h>
00079 #endif
00080 
00081 #if defined(alliant) && !defined(i860)
00082 /* Alliant FX/8 */
00083 # include <cncall.h>
00084 struct bu_semaphores {
00085         long    magic;
00086         char    c;
00087 };
00088 # define DEFINED_BU_SEMAPHORES  1
00089 #endif
00090 
00091 #if (defined(sgi) && defined(mips)) || (defined(__sgi) && defined(__mips))
00092 # define SGI_4D 1
00093 # define _SGI_SOURCE    1       /* IRIX 5.0.1 needs this to def M_BLKSZ */
00094 # define _BSD_TYPES     1       /* IRIX 5.0.1 botch in sys/prctl.h */
00095 # include <sys/types.h>
00096 # include <ulocks.h>
00097 /* ulocks.h #include's <limits.h> and <malloc.h> */
00098 /* ulocks.h #include's <task.h> for getpid stuff */
00099 /* task.h #include's <sys/prctl.h> */
00100 # include <malloc.h>
00101 /* <malloc.h> #include's <stddef.h> */
00102 
00103 #ifdef HAVE_SYS_WAIT_H
00104 #  include <sys/wait.h>
00105 #endif
00106 
00107 #ifdef _WIN32
00108 static char             bu_lockfile[] = "C:\\bu_lockXXXXXX";
00109 #else
00110 static char             bu_lockfile[] = "/usr/tmp/bu_lockXXXXXX";
00111 #endif
00112 
00113 static usptr_t          *bu_lockstuff = 0;
00114 extern int              _utrace;
00115 
00116 struct bu_semaphores {
00117         long    magic;
00118         ulock_t ltp;
00119 };
00120 # define DEFINED_BU_SEMAPHORES  1
00121 #endif /* SGI_4D */
00122 
00123 /* XXX Probably need to set _SGI_MP_SOURCE in machine.h */
00124 
00125 #ifdef ardent
00126 #       include <thread.h>
00127 struct bu_semaphores {
00128         long    magic;
00129         char    sem;
00130 };
00131 # define DEFINED_BU_SEMAPHORES  1
00132 #endif
00133 
00134 #if defined(convex) || defined(__convex__)
00135 struct bu_semaphores {
00136         long    magic;
00137         long    sem;
00138 };
00139 # define DEFINED_BU_SEMAPHORES  1
00140 #endif
00141 
00142 #if defined(n16)
00143 #       include <parallel.h>
00144 #       include <sys/sysadmin.h>
00145 struct bu_semaphores {
00146         long    magic;
00147         char    sem;
00148 };
00149 # define DEFINED_BU_SEMAPHORES  1
00150 #endif
00151 
00152 /*
00153  * multithreading support for SunOS 5.X / Solaris 2.x
00154  */
00155 #if SUNOS >= 52
00156 #       include <sys/unistd.h>
00157 #       include <thread.h>
00158 #       include <synch.h>
00159 struct bu_semaphores {
00160         long    magic;
00161         mutex_t mu;
00162 };
00163 # define DEFINED_BU_SEMAPHORES  1
00164 #endif  /* SUNOS */
00165 
00166 /*
00167  * multithread support built on POSIX Threads (pthread) library.
00168  */
00169 #ifdef HAVE_UNISTD_H
00170 #       include <unistd.h>
00171 #else
00172 #  ifdef HAVE_SYS_UNISTD_H
00173 #       include <sys/unistd.h>
00174 #  endif
00175 #endif
00176 #ifdef HAVE_PTHREAD_H
00177 #       include <pthread.h>
00178 #  if !defined(sgi)
00179 struct bu_semaphores {
00180         long    magic;
00181         pthread_mutex_t mu;
00182 };
00183 #       define DEFINED_BU_SEMAPHORES    1
00184 #  endif
00185 #endif
00186 
00187 
00188 #define BU_SEMAPHORE_MAGIC              0x62757365
00189 
00190 #if defined(SGI_4D)
00191 /**
00192  *                       B U _ S E M A P H O R E _ S G I _ I N I T
00193  */
00194 static void
00195 bu_semaphore_sgi_init()
00196 {
00197         /*
00198          *  First time through.
00199          *  Use this opportunity to tune malloc().  It needs it!
00200          *  Default for M_BLKSZ is 8k.
00201          */
00202         if( mallopt( M_BLKSZ, 128*1024 ) != 0 )
00203                 fprintf(stderr, "bu_semaphore_sgi_init: mallopt() failed\n");
00204 
00205         /* Now, set up the lock arena */
00206         (void)mktemp(bu_lockfile);
00207         if( bu_debug & BU_DEBUG_PARALLEL )  {
00208                 if( usconfig( CONF_LOCKTYPE, _USDEBUGPLUS ) == -1 )
00209                         perror("usconfig CONF_LOCKTYPE");
00210         }
00211         /*
00212          *  Note that libc mp debugging to stderr can be enabled by saying
00213          *      int _utrace=1;
00214          */
00215 
00216         /* Cause lock file to vanish on exit */
00217         usconfig(CONF_ARENATYPE, US_SHAREDONLY);
00218 
00219         /* Set maximum number of procs that can share this arena */
00220         usconfig(CONF_INITUSERS, bu_avail_cpus()+1);
00221 
00222         if( bu_debug & BU_DEBUG_PARALLEL )  {
00223                 /* This is a big performance hit, but may find bugs */
00224                 usconfig(CONF_LOCKTYPE, US_DEBUG);
00225         } else {
00226                 usconfig(CONF_LOCKTYPE, US_NODEBUG);
00227         }
00228 
00229         /* Initialize arena */
00230         bu_lockstuff = usinit(bu_lockfile);
00231         if (bu_lockstuff == 0) {
00232                 perror("usinit");
00233                 fprintf(stderr, "bu_semaphore_sgi_init: usinit(%s) failed, unable to allocate lock space\n", bu_lockfile);
00234                 exit(2);
00235         }
00236 }
00237 #endif
00238 
00239 #if defined(convex) || defined(__convex__)
00240 /**
00241  *                      B U _ C O N V E X _ A C Q U I R E
00242  */
00243 static void
00244 bu_convex_acquire(p)
00245 register long *p;
00246 {
00247         asm("getlck:");
00248         asm("   tas     @0(ap)");       /* try to set the lock */
00249         asm("   jbra.f  getlck");       /* loop until successful */
00250 }
00251 #endif /* convex */
00252 
00253 #if defined(PARALLEL) || defined(DEFINED_BU_SEMAPHORES)
00254 static unsigned int             bu_nsemaphores = 0;
00255 static struct bu_semaphores     *bu_semaphores = (struct bu_semaphores *)NULL;
00256 #endif
00257 
00258 /**
00259  *                      B U _ S E M A P H O R E _ I N I T
00260  *
00261  *  Prepare 'nsemaphores' independent critical section semaphores.
00262  *  Die on error.
00263  *  Takes the place of 'n' separate calls to old RES_INIT().
00264  *  Start by allocating array of "struct bu_semaphores", which has been
00265  *  arranged to contain whatever this system needs.
00266  *
00267  */
00268 void
00269 bu_semaphore_init(unsigned int nsemaphores)
00270 {
00271 #if !defined(PARALLEL) && !defined(DEFINED_BU_SEMAPHORES)
00272         return;                                 /* No support on this hardware */
00273 #else
00274         int     i;
00275 
00276         if( bu_nsemaphores != 0 )  return;      /* Already called */
00277         bu_semaphores = (struct bu_semaphores *)calloc(
00278                 nsemaphores,
00279                 sizeof(struct bu_semaphores) );
00280         if( !bu_semaphores )  {
00281                 fprintf(stderr, "bu_semaphore_init(): could not allocate space for %d semaphores of len %ld\n",
00282                         nsemaphores, (long)sizeof(struct bu_semaphores));
00283                 exit(2);
00284         }
00285 
00286         /*
00287          *  Begin vendor-specific initialization sections.
00288          */
00289 
00290 #       if defined(alliant)
00291         for( i=0; i < nsemaphores; i++ )  {
00292                 bu_semaphores[i].magic = BU_SEMAPHORE_MAGIC;
00293                 (void) initialize_lock( &bu_semaphores[i].c );
00294         }
00295 #       endif
00296 
00297 #       ifdef ardent
00298         for( i=0; i < nsemaphores; i++ )  {
00299                 bu_semaphores[i].magic = BU_SEMAPHORE_MAGIC;
00300                 bu_semaphores[i].sem = 1;       /* mark as released */
00301         }
00302 #       endif
00303 
00304 #       if defined(convex) || defined(__convex__)
00305         for( i=0; i < nsemaphores; i++ )  {
00306                 bu_semaphores[i].magic = BU_SEMAPHORE_MAGIC;
00307                 bu_semaphores[i].sem = 0;       /* mark as released */
00308         }
00309 #       endif
00310 
00311 #       ifdef CRAY
00312         for( i=0; i < nsemaphores; i++ )  {
00313                 bu_semaphores[i].magic = BU_SEMAPHORE_MAGIC;
00314                 LOCKASGN( &bu_semaphores[i].p );
00315         }
00316 #       endif /* CRAY */
00317 
00318 #       if defined(n16)
00319         /*
00320          *                      Encore MultiMax.
00321          *  While the manual suggests that one should use spin_create()
00322          *  to aquire a new control structure for spin locking, it turns
00323          *  out that the library support for that simply malloc()s a 1-byte
00324          *  area to contain the lock, and sets it to PAR_UNLOCKED.
00325          */
00326         for( i=0; i < nsemaphores; i++ )  {
00327                 bu_semaphores[i].magic = BU_SEMAPHORE_MAGIC;
00328                 bu_semaphores[i].sem = PAR_UNLOCKED;
00329         }
00330 #       endif
00331 
00332 #       ifdef SGI_4D
00333         bu_semaphore_sgi_init();
00334         for( i=0; i < nsemaphores; i++ )  {
00335                 bu_semaphores[i].magic = BU_SEMAPHORE_MAGIC;
00336                 if( (bu_semaphores[i].ltp = usnewlock(bu_lockstuff)) == NULL )  {
00337                         perror("usnewlock");
00338                         fprintf(stderr, "bu_semaphore_init: usnewlock() failed, unable to allocate lock %d\n", i);
00339                         exit(2);
00340                 }
00341         }
00342 #       endif
00343 
00344 #       if SUNOS
00345         for( i=0; i < nsemaphores; i++ )  {
00346                 bu_semaphores[i].magic = BU_SEMAPHORE_MAGIC;
00347                 if (mutex_init( &bu_semaphores[i].mu, USYNC_THREAD, NULL)) {
00348                         fprintf(stderr, "bu_semaphore_init(): mutex_init() failed on %d\n", i);
00349                         abort();
00350                 }
00351 
00352         }
00353 #       endif
00354 #       if defined(HAVE_PTHREAD_H) && !defined(sgi)
00355         for( i=0; i < nsemaphores; i++ )  {
00356                 bu_semaphores[i].magic = BU_SEMAPHORE_MAGIC;
00357                 if (pthread_mutex_init( &bu_semaphores[i].mu,  NULL)) {
00358                         fprintf(stderr, "bu_semaphore_init(): pthread_mutex_init() failed on %d\n", i);
00359                         abort();
00360                 }
00361         }
00362 #       endif
00363 
00364         /*
00365          *  This should be last thing done before returning, so that
00366          *  any subroutines called (e.g. bu_calloc()) won't think that
00367          *  parallel operation has begun yet, and do acquire/release.
00368          */
00369         bu_nsemaphores = nsemaphores;
00370 #endif  /* PARALLEL */
00371 }
00372 
00373 /**
00374  *                      B U _ S E M A P H O R E _ A C Q U I R E
00375  */
00376 void
00377 bu_semaphore_acquire(unsigned int i)
00378 {
00379 #if !defined(PARALLEL) && !defined(DEFINED_BU_SEMAPHORES)
00380         return;                                 /* No support on this hardware */
00381 #else
00382         if( bu_semaphores == NULL )  {
00383                 /* Semaphores not initialized yet.  Must be non-parallel */
00384                 return;
00385         }
00386 
00387         BU_CKMAG(bu_semaphores, BU_SEMAPHORE_MAGIC, "bu_semaphore");
00388 
00389         if( i >= bu_nsemaphores )  {
00390                 fprintf(stderr, "bu_semaphore_acquire(%d): semaphore # exceeds max of %d\n",
00391                         i, bu_nsemaphores);
00392                 abort();
00393         }
00394 
00395         BU_CKMAG(&bu_semaphores[i], BU_SEMAPHORE_MAGIC, "bu_semaphore");
00396 
00397         /*
00398          *  Begin vendor-specific initialization sections.
00399          */
00400 
00401 #       if defined(alliant)
00402         (void) lock( &bu_semaphores[i].c );
00403 #       endif
00404 
00405 #       ifdef ardent
00406         {
00407                 register long   *p = &bu_semaphores[i].sem;
00408                 while( SYNCH_Adr = p, !SYNCH_Val )  while( !*p );
00409         }
00410 #       endif
00411 
00412 #       if defined(convex) || defined(__convex__)
00413         bu_convex_acquire( &bu_semaphores[i].sem );
00414 #       endif
00415 
00416 #       ifdef CRAY
00417         LOCKON( &bu_semaphores[i].p );
00418 #       endif /* CRAY */
00419 
00420 #       if defined(n16)
00421         (void)spin_lock( (LOCK *)&bu_semaphores[i].sem );
00422 #       endif
00423 
00424 #       ifdef SGI_4D
00425         uswsetlock( bu_semaphores[i].ltp, 1000);
00426 #       endif
00427 
00428 #       if SUNOS
00429         if( mutex_lock( &bu_semaphores[i].mu ) )  {
00430                 fprintf(stderr, "bu_semaphore_acquire(): mutex_lock() failed on %d\n", i);
00431                 abort();
00432         }
00433 #       endif
00434 #       if defined(HAVE_PTHREAD_H) && !defined(sgi)
00435         if( pthread_mutex_lock( &bu_semaphores[i].mu ) )  {
00436                 fprintf(stderr, "bu_semaphore_acquire(): pthread_mutex_lock() failed on %d\n", i);
00437                 abort();
00438         }
00439 #       endif
00440 
00441 #endif
00442 }
00443 
00444 /**
00445  *                      B U _ S E M A P H O R E _ R E L E A S E
00446  */
00447 void
00448 bu_semaphore_release(unsigned int i)
00449 {
00450 #if !defined(PARALLEL) && !defined(DEFINED_BU_SEMAPHORES)
00451         return;                                 /* No support on this hardware */
00452 #else
00453         if( bu_semaphores == NULL )  {
00454                 /* Semaphores not initialized yet.  Must be non-parallel */
00455                 return;
00456         }
00457 
00458         BU_CKMAG(bu_semaphores, BU_SEMAPHORE_MAGIC, "bu_semaphore");
00459 
00460         if( i >= bu_nsemaphores )  {
00461                 fprintf(stderr, "bu_semaphore_release(%d): semaphore # exceeds max of %d\n",
00462                         i, bu_nsemaphores);
00463                 exit(3);
00464         }
00465 
00466         BU_CKMAG(&bu_semaphores[i], BU_SEMAPHORE_MAGIC, "bu_semaphore");
00467 
00468         /*
00469          *  Begin vendor-specific initialization sections.
00470          */
00471 
00472 #       if defined(alliant)
00473         (void) unlock( &bu_semaphores[i].c );
00474 #       endif
00475 
00476 #       ifdef ardent
00477         bu_semaphores[i].sem = 1;       /* release */
00478 #       endif
00479 
00480 #       if defined(convex) || defined(__convex__)
00481         bu_semaphores[i].sem = 0;       /* release */
00482 #       endif
00483 
00484 #       ifdef CRAY
00485         LOCKOFF( &bu_semaphores[i].p );
00486 #       endif /* CRAY */
00487 
00488 #       if defined(n16)
00489         (void)spin_unlock( (LOCK *)&bu_semaphores[i].sem );
00490 #       endif
00491 
00492 #       ifdef SGI_4D
00493         usunsetlock( bu_semaphores[i].ltp );
00494 #       endif
00495 
00496 #       if SUNOS
00497         if( mutex_unlock( &bu_semaphores[i].mu ) )  {
00498                 fprintf(stderr, "bu_semaphore_acquire(): mutex_unlock() failed on %d\n", i);
00499                 abort();
00500         }
00501 #       endif
00502 #       if defined(HAVE_PTHREAD_H) && !defined (sgi)
00503         if( pthread_mutex_unlock( &bu_semaphores[i].mu ) )  {
00504                 fprintf(stderr, "bu_semaphore_acquire(): pthread_mutex_unlock() failed on %d\n", i);
00505                 abort();
00506         }
00507 #       endif
00508 #endif
00509 }
00510 /*@}*/
00511 /*
00512  * Local Variables:
00513  * mode: C
00514  * tab-width: 8
00515  * c-basic-offset: 4
00516  * indent-tabs-mode: t
00517  * End:
00518  * ex: shiftwidth=4 tabstop=8
00519  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6