Back to index

plt-scheme  4.2.1
mzrt.c
Go to the documentation of this file.
00001 #include "schpriv.h"
00002 
00003 #ifdef MZ_USE_PLACES
00004 
00005 /************************************************************************/
00006 /************************************************************************/
00007 /************************************************************************/
00008 #define MZRT_INTERNAL
00009 #include "mzrt.h"
00010 #include "schgc.h"
00011 
00012 #ifdef MZ_XFORM
00013 START_XFORM_SUSPEND;
00014 #endif
00015 
00016 /* std C headers */
00017 #include <stdlib.h>
00018 #include <stdio.h>
00019 #include <errno.h>
00020 
00021 #include <../sconfig.h>
00022 
00023 /* platform headers */
00024 #ifdef WIN32
00025 # include <windows.h>
00026 #else
00027 # include <pthread.h>
00028 # include <signal.h>
00029 # include <unistd.h>
00030 # include <time.h>
00031 # if defined(UNIX_LIMIT_STACK) || defined(UNIX_LIMIT_FDSET_SIZE)
00032 #   include <signal.h>
00033 #   include <sys/time.h>
00034 #   include <sys/resource.h>
00035 # endif
00036 #endif
00037 
00038 void mzrt_set_user_break_handler(void (*user_break_handler)(int))
00039 {
00040 #ifdef WIN32
00041 #else
00042   signal(SIGINT, user_break_handler);
00043 #endif
00044 }
00045 
00046 static void rungdb() {
00047 #ifdef WIN32
00048 #else
00049   pid_t pid = getpid();
00050   char outbuffer[100];
00051   char inbuffer[10];
00052 
00053   fprintf(stderr, "pid # %i resume(r)/gdb(d)/exit(e)?\n", pid);
00054   fflush(stderr);
00055 
00056   while(1) {
00057     while(read(fileno(stdin), inbuffer, 10) <= 0){
00058       if(errno != EINTR){
00059         fprintf(stderr, "Error detected %i\n", errno);
00060       }
00061     }
00062     switch(inbuffer[0]) {
00063       case 'r':
00064         return;
00065         break;
00066       case 'd':
00067         snprintf(outbuffer, 100, "xterm -e gdb ./mzscheme3m %d &", pid);
00068         fprintf(stderr, "%s\n", outbuffer);
00069         system(outbuffer);
00070         break;
00071       case 'e':
00072       default:
00073         exit(1);
00074         break;
00075     }
00076   }
00077 #endif
00078 }
00079 
00080 static void segfault_handler(int signal_num) {
00081   pid_t pid = getpid();
00082   fprintf(stderr, "sig# %i pid# %i\n", signal_num, pid);
00083   rungdb();
00084 }
00085 
00086 
00087 void mzrt_set_segfault_debug_handler()
00088 {
00089 #ifdef WIN32
00090 #else
00091   signal(SIGSEGV, segfault_handler);
00092 #endif
00093 }
00094 
00095 void mzrt_sleep(int seconds)
00096 {
00097 #ifdef WIN32
00098 #else
00099   struct timespec set;
00100   struct timespec rem;
00101   set.tv_sec  = seconds;
00102   set.tv_nsec = 0;
00103   rem.tv_sec  = 0;
00104   rem.tv_nsec = 0;
00105   while ((-1 == nanosleep(&set, &rem))) {
00106     //fprintf(stderr, "%i %i INITIAL\n", set.tv_sec, set.tv_nsec);
00107     //fprintf(stderr, "%i %i LEFT\n", rem.tv_sec, rem.tv_nsec);
00108     set = rem;
00109     //fprintf(stderr, "%i %i NOW\n", set.tv_sec, set.tv_nsec);
00110   }
00111 #endif
00112 }
00113 
00114 #ifdef MZ_XFORM
00115 END_XFORM_SUSPEND;
00116 #endif
00117 
00118 /***********************************************************************/
00119 /*                Atomic Ops                                           */
00120 /***********************************************************************/
00121 
00122 MZ_INLINE uint32_t mzrt_atomic_add_32(volatile unsigned int *counter, unsigned int value) {
00123 #ifdef WIN32
00124 # if defined(__MINGW32__)
00125   return InterlockedExchangeAdd((long *)counter, value);
00126 # else
00127   return InterlockedExchangeAdd(counter, value);
00128 # endif
00129 
00130 #elif defined (__GNUC__) && (defined(__i386__) || defined(__x86_64__))
00131   asm volatile ("lock; xaddl %0,%1"
00132       : "=r" (value), "=m" (*counter)
00133       : "0" (value), "m" (*counter)
00134       : "memory", "cc");
00135   return value;
00136 #else
00137 #error !!!Atomic ops not provided!!!
00138 #endif
00139 }
00140 
00141 /* returns the pre-incremented value */
00142 MZ_INLINE uint32_t mzrt_atomic_incr_32(volatile unsigned int *counter) {
00143   return mzrt_atomic_add_32(counter, 1);
00144 }
00145 
00146 /***********************************************************************/
00147 /*                Threads                                              */
00148 /***********************************************************************/
00149 typedef struct mzrt_thread_stub_data {
00150   void * (*start_proc)(void *);
00151   void *data;
00152   mz_proc_thread *thread;
00153 } mzrt_thread_stub_data;
00154 
00155 void *mzrt_thread_stub(void *data){
00156   mzrt_thread_stub_data *stub_data  = (mzrt_thread_stub_data*) data;
00157   void * (*start_proc)(void *)        = stub_data->start_proc;
00158   void *start_proc_data               = stub_data->data;
00159   proc_thread_self                    = stub_data->thread;
00160 
00161   free(data);
00162 
00163   return start_proc(start_proc_data);
00164 }
00165 
00166 unsigned int mz_proc_thread_self() {
00167 #ifdef WIN32
00168 #error !!!mz_proc_thread_id not implemented!!!
00169 #else
00170   return (unsigned int) pthread_self();
00171 #endif
00172 }
00173 
00174 unsigned int mz_proc_thread_id(mz_proc_thread* thread) {
00175 
00176   return (unsigned int) thread->threadid;
00177 }
00178 
00179 mz_proc_thread* mzrt_proc_first_thread_init() {
00180   /* initialize mz_proc_thread struct for first thread myself that wasn't created with mz_proc_thread_create,
00181    * so it can communicate with other mz_proc_thread_created threads via pt_mboxes */
00182   mz_proc_thread *thread = (mz_proc_thread*)malloc(sizeof(mz_proc_thread));
00183   thread->mbox      = pt_mbox_create();
00184   thread->threadid  = mz_proc_thread_self();
00185   proc_thread_self  = thread;
00186   return thread;
00187 }
00188 
00189 mz_proc_thread* mz_proc_thread_create(mz_proc_thread_start start_proc, void* data) {
00190   mz_proc_thread *thread = (mz_proc_thread*)malloc(sizeof(mz_proc_thread));
00191 #ifdef MZ_PRECISE_GC
00192   mzrt_thread_stub_data *stub_data = (mzrt_thread_stub_data*)malloc(sizeof(mzrt_thread_stub_data));
00193   thread->mbox = pt_mbox_create();
00194   stub_data->start_proc = start_proc;
00195   stub_data->data       = data;
00196   stub_data->thread     = thread;
00197 #   ifdef WIN32
00198   thread->threadid = CreateThread(NULL, 0, start_proc, data, 0, NULL);
00199 #   else
00200   pthread_create(&thread->threadid, NULL, mzrt_thread_stub, stub_data);
00201 #   endif
00202 #else
00203 #   ifdef WIN32
00204   thread->threadid = GC_CreateThread(NULL, 0, start_proc, data, 0, NULL);
00205 #   else
00206   GC_pthread_create(&thread->threadid, NULL, start_proc, data);
00207 #   endif
00208 #endif
00209   return thread;
00210 }
00211 
00212 void * mz_proc_thread_wait(mz_proc_thread *thread) {
00213 #ifdef WIN32
00214   DWORD rc;
00215   WaitForSingleObject(thread->threadid,INFINITE);
00216   GetExitCodeThread(thread->threadid, &rc);
00217   return (void *) rc;
00218 #else
00219   void *rc;
00220 #   ifndef MZ_PRECISE_GC
00221   GC_pthread_join(thread->threadid, &rc);
00222 #   else
00223   pthread_join(thread->threadid, &rc);
00224 #   endif
00225   return rc;
00226 #endif
00227 }
00228 
00229 /***********************************************************************/
00230 /*                RW Lock                                              */
00231 /***********************************************************************/
00232 
00233 /* Unix **************************************************************/
00234 
00235 #ifndef WIN32
00236 
00237 #ifdef MZ_XFORM
00238 START_XFORM_SUSPEND;
00239 #endif
00240 
00241 struct mzrt_rwlock {
00242   pthread_rwlock_t lock;
00243 };
00244 
00245 int mzrt_rwlock_create(mzrt_rwlock **lock) {
00246   *lock = malloc(sizeof(mzrt_rwlock));
00247   return pthread_rwlock_init(&(*lock)->lock, NULL);
00248 }
00249 
00250 int mzrt_rwlock_rdlock(mzrt_rwlock *lock) {
00251   return pthread_rwlock_rdlock(&lock->lock);
00252 }
00253 
00254 int mzrt_rwlock_wrlock(mzrt_rwlock *lock) {
00255   return pthread_rwlock_wrlock(&lock->lock);
00256 }
00257 
00258 int mzrt_rwlock_tryrdlock(mzrt_rwlock *lock) {
00259   return pthread_rwlock_tryrdlock(&lock->lock);
00260 }
00261 
00262 int mzrt_rwlock_trywrlock(mzrt_rwlock *lock) {
00263   return pthread_rwlock_trywrlock(&lock->lock);
00264 }
00265 int mzrt_rwlock_unlock(mzrt_rwlock *lock) {
00266   return pthread_rwlock_unlock(&lock->lock);
00267 }
00268 
00269 int mzrt_rwlock_destroy(mzrt_rwlock *lock) {
00270   return pthread_rwlock_destroy(&lock->lock);
00271 }
00272 
00273 struct mzrt_mutex {
00274   pthread_mutex_t mutex;
00275 };
00276 
00277 int mzrt_mutex_create(mzrt_mutex **mutex) {
00278   *mutex = malloc(sizeof(struct mzrt_mutex));
00279   return pthread_mutex_init(&(*mutex)->mutex, NULL);
00280 }
00281 
00282 int mzrt_mutex_lock(mzrt_mutex *mutex) {
00283   return pthread_mutex_lock(&mutex->mutex);
00284 }
00285 
00286 int mzrt_mutex_trylock(mzrt_mutex *mutex) {
00287   return pthread_mutex_trylock(&mutex->mutex);
00288 }
00289 
00290 int mzrt_mutex_unlock(mzrt_mutex *mutex) {
00291   return pthread_mutex_unlock(&mutex->mutex);
00292 }
00293 
00294 int mzrt_mutex_destroy(mzrt_mutex *mutex) {
00295   return pthread_mutex_destroy(&mutex->mutex);
00296 }
00297 
00298 struct mzrt_cond {
00299   pthread_cond_t cond;
00300 };
00301 
00302 int mzrt_cond_create(mzrt_cond **cond) {
00303   *cond = malloc(sizeof(struct mzrt_cond));
00304   return pthread_cond_init(&(*cond)->cond, NULL);
00305 }
00306 
00307 int mzrt_cond_wait(mzrt_cond *cond, mzrt_mutex *mutex) {
00308   return pthread_cond_wait(&cond->cond, &mutex->mutex);
00309 }
00310 
00311 int mzrt_cond_timedwait(mzrt_cond *cond, mzrt_mutex *mutex, long seconds, long nanoseconds) {
00312   struct timespec timeout;
00313   timeout.tv_sec  = seconds;
00314   timeout.tv_nsec = nanoseconds;
00315   return pthread_cond_timedwait(&cond->cond, &mutex->mutex, &timeout);
00316 }
00317 
00318 int mzrt_cond_signal(mzrt_cond *cond) {
00319   return pthread_cond_signal(&cond->cond);
00320 }
00321 
00322 int mzrt_cond_broadcast(mzrt_cond *cond) {
00323   return pthread_cond_broadcast(&cond->cond);
00324 }
00325 
00326 int mzrt_cond_destroy(mzrt_cond *cond) {
00327   return pthread_cond_destroy(&cond->cond);
00328 }
00329 
00330 /****************** PROCESS THREAD MAIL BOX *******************************/
00331 
00332 pt_mbox *pt_mbox_create() {
00333   pt_mbox *mbox = (pt_mbox *)malloc(sizeof(pt_mbox));
00334   mbox->count = 0;
00335   mbox->in    = 0;
00336   mbox->out   = 0;
00337   mzrt_mutex_create(&mbox->mutex);
00338   mzrt_cond_create(&mbox->nonempty);
00339   mzrt_cond_create(&mbox->nonfull);
00340   return mbox;
00341 }
00342 
00343 void pt_mbox_send(pt_mbox *mbox, int type, void *payload, pt_mbox *origin) {
00344   mzrt_mutex_lock(mbox->mutex);
00345   while ( mbox->count == 5 ) {
00346     mzrt_cond_wait(mbox->nonfull, mbox->mutex);
00347   }
00348   mbox->queue[mbox->in].type = type;
00349   mbox->queue[mbox->in].payload = payload;
00350   mbox->queue[mbox->in].origin = origin;
00351   mbox->in = (mbox->in + 1) % 5;
00352   mbox->count++;
00353   mzrt_cond_signal(mbox->nonempty);
00354   mzrt_mutex_unlock(mbox->mutex);
00355 }
00356 
00357 void pt_mbox_recv(pt_mbox *mbox, int *type, void **payload, pt_mbox **origin){
00358   mzrt_mutex_lock(mbox->mutex);
00359   while ( mbox->count == 0 ) {
00360     mzrt_cond_wait(mbox->nonempty, mbox->mutex);
00361   }
00362   *type    = mbox->queue[mbox->out].type;
00363   *payload = mbox->queue[mbox->out].payload;
00364   *origin  = mbox->queue[mbox->out].origin;
00365   mbox->out = (mbox->out + 1) % 5;
00366   mbox->count--;
00367   mzrt_cond_signal(mbox->nonfull);
00368   mzrt_mutex_unlock(mbox->mutex);
00369 }
00370 
00371 void pt_mbox_send_recv(pt_mbox *mbox, int type, void *payload, pt_mbox *origin, int *return_type, void **return_payload) {
00372   pt_mbox *return_origin;
00373   pt_mbox_send(mbox, type, payload, origin);
00374   pt_mbox_recv(origin, return_type, return_payload, &return_origin);
00375 }
00376 
00377 void pt_mbox_destroy(pt_mbox *mbox) {
00378   mzrt_mutex_destroy(mbox->mutex);
00379   mzrt_cond_destroy(mbox->nonempty);
00380   mzrt_cond_destroy(mbox->nonfull);
00381   free(mbox);
00382 }
00383 
00384 #ifdef MZ_XFORM
00385 END_XFORM_SUSPEND;
00386 #endif
00387 
00388 #endif
00389 
00390 /* Windows **************************************************************/
00391 
00392 #ifdef WIN32
00393 
00394 #ifdef MZ_XFORM
00395 START_XFORM_SUSPEND;
00396 #endif
00397 
00398 typedef struct mzrt_rwlock {
00399   HANDLE readEvent;
00400   HANDLE writeMutex;
00401   unsigned long readers;
00402 } mzrt_rwlock;
00403 
00404 int mzrt_rwlock_create(mzrt_rwlock **lock) {
00405   *lock = malloc(sizeof(mzrt_rwlock));
00406   (*lock)->readers = 0;
00407   /* CreateEvent(LPSECURITY_ATTRIBUTES, manualReset, initiallySignaled, LPCSTR name) */
00408   if (! ((*lock)->readEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
00409     return 0;
00410   if (! ((*lock)->writeMutex = CreateMutex(NULL, FALSE, NULL)))
00411     return 0;
00412 
00413   return 1;
00414 }
00415 
00416 static int get_win32_os_error() {
00417   return 0;
00418 }
00419 
00420 static int mzrt_rwlock_rdlock_worker(mzrt_rwlock *lock, DWORD millis) {
00421   DWORD rc = WaitForSingleObject(lock->writeMutex, millis);
00422   if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT );
00423     return 0;
00424 
00425   InterlockedIncrement(&lock->readers);
00426 
00427   if (! ResetEvent(lock->readEvent))
00428     return 0;
00429 
00430   if (!ReleaseMutex(lock->writeMutex))
00431     return 0;
00432 
00433   return 1;
00434 }
00435 
00436 static int mzrt_rwlock_wrlock_worker(mzrt_rwlock *lock, DWORD millis) {
00437   DWORD rc = WaitForSingleObject(lock->writeMutex, millis);
00438   if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT );
00439     return 0;
00440 
00441   if (lock->readers) {
00442     if (millis) {
00443       rc = WaitForSingleObject(lock->readEvent, millis);
00444     }
00445     else {
00446       rc = WAIT_TIMEOUT;
00447     }
00448 
00449     if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT );
00450       return 0;
00451   }
00452 
00453   return 1;
00454 }
00455 
00456 int mzrt_rwlock_rdlock(mzrt_rwlock *lock) {
00457   return mzrt_rwlock_rdlock_worker(lock, INFINITE);
00458 }
00459 
00460 int mzrt_rwlock_wrlock(mzrt_rwlock *lock) {
00461   return mzrt_rwlock_wrlock_worker(lock, INFINITE);
00462 }
00463 
00464 int mzrt_rwlock_tryrdlock(mzrt_rwlock *lock) {
00465   return mzrt_rwlock_rdlock_worker(lock, 0);
00466 }
00467 
00468 int mzrt_rwlock_trywrlock(mzrt_rwlock *lock) {
00469   return mzrt_rwlock_wrlock_worker(lock, 0);
00470 }
00471 
00472 int mzrt_rwlock_unlock(mzrt_rwlock *lock) {
00473   DWORD rc = 0;
00474   if (!ReleaseMutex(lock->writeMutex)) {
00475     rc = get_win32_os_error();
00476   }
00477 
00478   if (rc == ERROR_NOT_OWNER) {
00479     if (lock->readers && !InterlockedDecrement(&lock->readers) && !SetEvent(lock->readEvent)) {
00480       rc = get_win32_os_error();
00481     }
00482     else {
00483       rc = 0;
00484     }
00485   }
00486 
00487   return !rc;
00488 }
00489 
00490 int mzrt_rwlock_destroy(mzrt_rwlock *lock) {
00491   int rc = 1;
00492   rc &= CloseHandle(lock->readEvent);
00493   rc &= CloseHandle(lock->writeMutex);
00494   return rc; 
00495 }
00496 
00497 struct mzrt_mutex {
00498   CRITICAL_SECTION critical_section;
00499 };
00500 
00501 int mzrt_mutex_create(mzrt_mutex **mutex) {
00502   *mutex = malloc(sizeof(mzrt_mutex));
00503   InitializeCriticalSection(&(*mutex)->critical_section);
00504   return 0;
00505 }
00506 
00507 int mzrt_mutex_lock(mzrt_mutex *mutex) {
00508   EnterCriticalSection(&(*mutex)->critical_section);
00509   return 0;
00510 }
00511 
00512 int mzrt_mutex_trylock(mzrt_mutex *mutex) {
00513   if (!TryEnterCriticalSection(&(*mutex)->critical_section))
00514     return 1;
00515   return 0;
00516 }
00517 
00518 int mzrt_mutex_unlock(mzrt_mutex *mutex) {
00519   LeaveCriticalSection(&(*mutex)->critical_section);
00520   return 0;
00521 }
00522 
00523 int mzrt_mutex_destroy(mzrt_mutex *mutex) {
00524   DeleteCriticalSection(&(*mutex)->critical_section);
00525   return 0;
00526 }
00527 
00528 struct mzrt_cond {
00529   pthread_cond_t cond;
00530 };
00531 
00532 int mzrt_cond_create(mzrt_cond **cond) {
00533   *cond = malloc(sizeof(mzrt_cond));
00534   return pthread_cond_init(&(*cond)->cond, NULL);
00535 }
00536 
00537 int mzrt_cond_wait(mzrt_cond *cond, mzrt_mutex *mutex) {
00538   return pthread_cond_wait(&cond->cond, &mutex->mutex);
00539 }
00540 
00541 int mzrt_cond_timedwait(mzrt_cond *cond, mzrt_mutex *mutex) {
00542   return pthread_cond_timedwait(&cond->cond, &mutex->mutex);
00543 }
00544 
00545 int mzrt_cond_signal(mzrt_cond *cond) {
00546   return pthread_cond_signal(&cond->cond);
00547 }
00548 
00549 int mzrt_cond_broadcast(mzrt_cond *cond) {
00550   return pthread_cond_broadcast(&cond->cond);
00551 }
00552 
00553 int mzrt_cond_destroy(mzrt_cond *cond) {
00554   return pthread_cond_destroy(&cond->cond);
00555 }
00556 
00557 #ifdef MZ_XFORM
00558 END_XFORM_SUSPEND;
00559 #endif
00560 
00561 #endif
00562 
00563 /************************************************************************/
00564 /************************************************************************/
00565 /************************************************************************/
00566 
00567 #endif