home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Python / thread_sgi.h < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-25  |  11.8 KB  |  504 lines

  1.  
  2. #ifdef WITH_SGI_DL
  3. #define USE_DL
  4. #endif
  5.  
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <signal.h>
  9. #include <sys/types.h>
  10. #include <sys/wait.h>
  11. #include <sys/prctl.h>
  12. #include <ulocks.h>
  13. #include <errno.h>
  14.  
  15. #define HDR_SIZE    2680    /* sizeof(ushdr_t) */
  16. #define MAXPROC        100    /* max # of threads that can be started */
  17.  
  18. static usptr_t *shared_arena;
  19. static ulock_t count_lock;    /* protection for some variables */
  20. static ulock_t wait_lock;    /* lock used to wait for other threads */
  21. static int waiting_for_threads;    /* protected by count_lock */
  22. static int nthreads;        /* protected by count_lock */
  23. static int exit_status;
  24. #ifndef NO_EXIT_PROG
  25. static int do_exit;        /* indicates that the program is to exit */
  26. #endif
  27. static int exiting;        /* we're already exiting (for maybe_exit) */
  28. static pid_t my_pid;        /* PID of main thread */
  29. static struct pidlist {
  30.     pid_t parent;
  31.     pid_t child;
  32. } pidlist[MAXPROC];    /* PIDs of other threads; protected by count_lock */
  33. static int maxpidindex;        /* # of PIDs in pidlist */
  34.  
  35. #ifndef NO_EXIT_PROG
  36. /*
  37.  * This routine is called as a signal handler when another thread
  38.  * exits.  When that happens, we must see whether we have to exit as
  39.  * well (because of an PyThread_exit_prog()) or whether we should continue on.
  40.  */
  41. static void exit_sig(void)
  42. {
  43.     d2printf(("exit_sig called\n"));
  44.     if (exiting && getpid() == my_pid) {
  45.         d2printf(("already exiting\n"));
  46.         return;
  47.     }
  48.     if (do_exit) {
  49.         d2printf(("exiting in exit_sig\n"));
  50. #ifdef Py_DEBUG
  51.         if ((thread_debug & 8) == 0)
  52.             thread_debug &= ~1; /* don't produce debug messages */
  53. #endif
  54.         PyThread_exit_thread();
  55.     }
  56. }
  57.  
  58. /*
  59.  * This routine is called when a process calls exit().  If that wasn't
  60.  * done from the library, we do as if an PyThread_exit_prog() was intended.
  61.  */
  62. static void maybe_exit(void)
  63. {
  64.     dprintf(("maybe_exit called\n"));
  65.     if (exiting) {
  66.         dprintf(("already exiting\n"));
  67.         return;
  68.     }
  69.     PyThread_exit_prog(0);
  70. }
  71. #endif /* NO_EXIT_PROG */
  72.  
  73. /*
  74.  * Initialization.
  75.  */
  76. static void PyThread__init_thread(void)
  77. {
  78. #ifndef NO_EXIT_PROG
  79.     struct sigaction s;
  80. #endif /* NO_EXIT_PROG */
  81. #ifdef USE_DL
  82.     long addr, size;
  83. #endif /* USE_DL */
  84.  
  85.  
  86. #ifdef USE_DL
  87.     if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
  88.         perror("usconfig - CONF_INITSIZE (check)");
  89.     if (usconfig(CONF_INITSIZE, size) < 0)
  90.         perror("usconfig - CONF_INITSIZE (reset)");
  91.     addr = (long) dl_getrange(size + HDR_SIZE);
  92.     dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size));
  93.     errno = 0;
  94.     if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
  95.         perror("usconfig - CONF_ATTACHADDR (set)");
  96. #endif /* USE_DL */
  97.     if (usconfig(CONF_INITUSERS, 16) < 0)
  98.         perror("usconfig - CONF_INITUSERS");
  99.     my_pid = getpid();    /* so that we know which is the main thread */
  100. #ifndef NO_EXIT_PROG
  101.     atexit(maybe_exit);
  102.     s.sa_handler = exit_sig;
  103.     sigemptyset(&s.sa_mask);
  104.     /*sigaddset(&s.sa_mask, SIGUSR1);*/
  105.     s.sa_flags = 0;
  106.     sigaction(SIGUSR1, &s, 0);
  107.     if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
  108.         perror("prctl - PR_SETEXITSIG");
  109. #endif /* NO_EXIT_PROG */
  110.     if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
  111.         perror("usconfig - CONF_ARENATYPE");
  112.     usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
  113. #ifdef Py_DEBUG
  114.     if (thread_debug & 4)
  115.         usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
  116.     else if (thread_debug & 2)
  117.         usconfig(CONF_LOCKTYPE, US_DEBUG);
  118. #endif /* Py_DEBUG */
  119.     if ((shared_arena = usinit(tmpnam(0))) == 0)
  120.         perror("usinit");
  121. #ifdef USE_DL
  122.     if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
  123.         perror("usconfig - CONF_ATTACHADDR (reset)");
  124. #endif /* USE_DL */
  125.     if ((count_lock = usnewlock(shared_arena)) == NULL)
  126.         perror("usnewlock (count_lock)");
  127.     (void) usinitlock(count_lock);
  128.     if ((wait_lock = usnewlock(shared_arena)) == NULL)
  129.         perror("usnewlock (wait_lock)");
  130.     dprintf(("arena start: %p, arena size: %ld\n",  shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
  131. }
  132.  
  133. /*
  134.  * Thread support.
  135.  */
  136.  
  137. static void clean_threads(void)
  138. {
  139.     int i, j;
  140.     pid_t mypid, pid;
  141.  
  142.     /* clean up any exited threads */
  143.     mypid = getpid();
  144.     i = 0;
  145.     while (i < maxpidindex) {
  146.         if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
  147.             pid = waitpid(pid, 0, WNOHANG);
  148.             if (pid > 0) {
  149.                 /* a thread has exited */
  150.                 pidlist[i] = pidlist[--maxpidindex];
  151.                 /* remove references to children of dead proc */
  152.                 for (j = 0; j < maxpidindex; j++)
  153.                     if (pidlist[j].parent == pid)
  154.                         pidlist[j].child = -1;
  155.                 continue; /* don't increment i */
  156.             }
  157.         }
  158.         i++;
  159.     }
  160.     /* clean up the list */
  161.     i = 0;
  162.     while (i < maxpidindex) {
  163.         if (pidlist[i].child == -1) {
  164.             pidlist[i] = pidlist[--maxpidindex];
  165.             continue; /* don't increment i */
  166.         }
  167.         i++;
  168.     }
  169. }
  170.  
  171. int PyThread_start_new_thread(void (*func)(void *), void *arg)
  172. {
  173. #ifdef USE_DL
  174.     long addr, size;
  175.     static int local_initialized = 0;
  176. #endif /* USE_DL */
  177.     int success = 0;    /* init not needed when SOLARIS_THREADS and */
  178.                 /* C_THREADS implemented properly */
  179.  
  180.     dprintf(("PyThread_start_new_thread called\n"));
  181.     if (!initialized)
  182.         PyThread_init_thread();
  183.     switch (ussetlock(count_lock)) {
  184.     case 0: return 0;
  185.     case -1: perror("ussetlock (count_lock)");
  186.     }
  187.     if (maxpidindex >= MAXPROC)
  188.         success = -1;
  189.     else {
  190. #ifdef USE_DL
  191.         if (!local_initialized) {
  192.             if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
  193.                 perror("usconfig - CONF_INITSIZE (check)");
  194.             if (usconfig(CONF_INITSIZE, size) < 0)
  195.                 perror("usconfig - CONF_INITSIZE (reset)");
  196.             addr = (long) dl_getrange(size + HDR_SIZE);
  197.             dprintf(("trying to use addr %p-%p for sproc\n",
  198.                  addr, addr+size));
  199.             errno = 0;
  200.             if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
  201.                 errno != 0)
  202.                 perror("usconfig - CONF_ATTACHADDR (set)");
  203.         }
  204. #endif /* USE_DL */
  205.         clean_threads();
  206.         if ((success = sproc(func, PR_SALL, arg)) < 0)
  207.             perror("sproc");
  208. #ifdef USE_DL
  209.         if (!local_initialized) {
  210.             if (usconfig(CONF_ATTACHADDR, addr) < 0)
  211.                 /* reset address */
  212.                 perror("usconfig - CONF_ATTACHADDR (reset)");
  213.             local_initialized = 1;
  214.         }
  215. #endif /* USE_DL */
  216.         if (success >= 0) {
  217.             nthreads++;
  218.             pidlist[maxpidindex].parent = getpid();
  219.             pidlist[maxpidindex++].child = success;
  220.             dprintf(("pidlist[%d] = %d\n",
  221.                  maxpidindex-1, success));
  222.         }
  223.     }
  224.     if (usunsetlock(count_lock) < 0)
  225.         perror("usunsetlock (count_lock)");
  226.     return success < 0 ? 0 : 1;
  227. }
  228.  
  229. long PyThread_get_thread_ident(void)
  230. {
  231.     return getpid();
  232. }
  233.  
  234. static void do_PyThread_exit_thread(int no_cleanup)
  235. {
  236.     dprintf(("PyThread_exit_thread called\n"));
  237.     if (!initialized)
  238.         if (no_cleanup)
  239.             _exit(0);
  240.         else
  241.             exit(0);
  242.     if (ussetlock(count_lock) < 0)
  243.         perror("ussetlock (count_lock)");
  244.     nthreads--;
  245.     if (getpid() == my_pid) {
  246.         /* main thread; wait for other threads to exit */
  247.         exiting = 1;
  248. #ifndef NO_EXIT_PROG
  249.         if (do_exit) {
  250.             int i;
  251.  
  252.             /* notify other threads */
  253.             clean_threads();
  254.             if (nthreads >= 0) {
  255.                 dprintf(("kill other threads\n"));
  256.                 for (i = 0; i < maxpidindex; i++)
  257.                     if (pidlist[i].child > 0)
  258.                         (void) kill(pidlist[i].child,
  259.                                 SIGKILL);
  260.                 _exit(exit_status);
  261.             }
  262.         }
  263. #endif /* NO_EXIT_PROG */
  264.         waiting_for_threads = 1;
  265.         if (ussetlock(wait_lock) < 0)
  266.             perror("ussetlock (wait_lock)");
  267.         for (;;) {
  268.             if (nthreads < 0) {
  269.                 dprintf(("really exit (%d)\n", exit_status));
  270.                 if (no_cleanup)
  271.                     _exit(exit_status);
  272.                 else
  273.                     exit(exit_status);
  274.             }
  275.             if (usunsetlock(count_lock) < 0)
  276.                 perror("usunsetlock (count_lock)");
  277.             dprintf(("waiting for other threads (%d)\n", nthreads));
  278.             if (ussetlock(wait_lock) < 0)
  279.                 perror("ussetlock (wait_lock)");
  280.             if (ussetlock(count_lock) < 0)
  281.                 perror("ussetlock (count_lock)");
  282.         }
  283.     }
  284.     /* not the main thread */
  285.     if (waiting_for_threads) {
  286.         dprintf(("main thread is waiting\n"));
  287.         if (usunsetlock(wait_lock) < 0)
  288.             perror("usunsetlock (wait_lock)");
  289.     }
  290. #ifndef NO_EXIT_PROG
  291.     else if (do_exit)
  292.         (void) kill(my_pid, SIGUSR1);
  293. #endif /* NO_EXIT_PROG */
  294.     if (usunsetlock(count_lock) < 0)
  295.         perror("usunsetlock (count_lock)");
  296.     _exit(0);
  297. }
  298.  
  299. void PyThread_exit_thread(void)
  300. {
  301.     do_PyThread_exit_thread(0);
  302. }
  303.  
  304. void PyThread__exit_thread(void)
  305. {
  306.     do_PyThread_exit_thread(1);
  307. }
  308.  
  309. #ifndef NO_EXIT_PROG
  310. static void do_PyThread_exit_prog(int status, int no_cleanup)
  311. {
  312.     dprintf(("PyThread_exit_prog(%d) called\n", status));
  313.     if (!initialized)
  314.         if (no_cleanup)
  315.             _exit(status);
  316.         else
  317.             exit(status);
  318.     do_exit = 1;
  319.     exit_status = status;
  320.     do_PyThread_exit_thread(no_cleanup);
  321. }
  322.  
  323. void PyThread_exit_prog(int status)
  324. {
  325.     do_PyThread_exit_prog(status, 0);
  326. }
  327.  
  328. void PyThread__exit_prog(int status)
  329. {
  330.     do_PyThread_exit_prog(status, 1);
  331. }
  332. #endif /* NO_EXIT_PROG */
  333.  
  334. /*
  335.  * Lock support.
  336.  */
  337. PyThread_type_lock PyThread_allocate_lock(void)
  338. {
  339.     ulock_t lock;
  340.  
  341.     dprintf(("PyThread_allocate_lock called\n"));
  342.     if (!initialized)
  343.         PyThread_init_thread();
  344.  
  345.     if ((lock = usnewlock(shared_arena)) == NULL)
  346.         perror("usnewlock");
  347.     (void) usinitlock(lock);
  348.     dprintf(("PyThread_allocate_lock() -> %p\n", lock));
  349.     return (PyThread_type_lock) lock;
  350. }
  351.  
  352. void PyThread_free_lock(PyThread_type_lock lock)
  353. {
  354.     dprintf(("PyThread_free_lock(%p) called\n", lock));
  355.     usfreelock((ulock_t) lock, shared_arena);
  356. }
  357.  
  358. int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
  359. {
  360.     int success;
  361.  
  362.     dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
  363.     errno = 0;        /* clear it just in case */
  364.     if (waitflag)
  365.         success = ussetlock((ulock_t) lock);
  366.     else
  367.         success = uscsetlock((ulock_t) lock, 1); /* Try it once */
  368.     if (success < 0)
  369.         perror(waitflag ? "ussetlock" : "uscsetlock");
  370.     dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
  371.     return success;
  372. }
  373.  
  374. void PyThread_release_lock(PyThread_type_lock lock)
  375. {
  376.     dprintf(("PyThread_release_lock(%p) called\n", lock));
  377.     if (usunsetlock((ulock_t) lock) < 0)
  378.         perror("usunsetlock");
  379. }
  380.  
  381. /*
  382.  * Semaphore support.
  383.  */
  384. PyThread_type_sema PyThread_allocate_sema(int value)
  385. {
  386.     usema_t *sema;
  387.     dprintf(("PyThread_allocate_sema called\n"));
  388.     if (!initialized)
  389.         PyThread_init_thread();
  390.  
  391.     if ((sema = usnewsema(shared_arena, value)) == NULL)
  392.         perror("usnewsema");
  393.     dprintf(("PyThread_allocate_sema() -> %p\n",  sema));
  394.     return (PyThread_type_sema) sema;
  395. }
  396.  
  397. void PyThread_free_sema(PyThread_type_sema sema)
  398. {
  399.     dprintf(("PyThread_free_sema(%p) called\n",  sema));
  400.     usfreesema((usema_t *) sema, shared_arena);
  401. }
  402.  
  403. int PyThread_down_sema(PyThread_type_sema sema, int waitflag)
  404. {
  405.     int success;
  406.  
  407.     dprintf(("PyThread_down_sema(%p) called\n",  sema));
  408.     if (waitflag)
  409.         success = uspsema((usema_t *) sema);
  410.     else
  411.         success = uscpsema((usema_t *) sema);
  412.     if (success < 0)
  413.         perror(waitflag ? "uspsema" : "uscpsema");
  414.     dprintf(("PyThread_down_sema(%p) return\n",  sema));
  415.     return success;
  416. }
  417.  
  418. void PyThread_up_sema(PyThread_type_sema sema)
  419. {
  420.     dprintf(("PyThread_up_sema(%p)\n",  sema));
  421.     if (usvsema((usema_t *) sema) < 0)
  422.         perror("usvsema");
  423. }
  424.  
  425. /*
  426.  * Per-thread data ("key") support.
  427.  */
  428.  
  429. struct key {
  430.     struct key *next;
  431.     long id;
  432.     int key;
  433.     void *value;
  434. };
  435.  
  436. static struct key *keyhead = NULL;
  437. static int nkeys = 0;
  438. static PyThread_type_lock keymutex = NULL;
  439.  
  440. static struct key *find_key(int key, void *value)
  441. {
  442.     struct key *p;
  443.     long id = PyThread_get_thread_ident();
  444.     for (p = keyhead; p != NULL; p = p->next) {
  445.         if (p->id == id && p->key == key)
  446.             return p;
  447.     }
  448.     if (value == NULL)
  449.         return NULL;
  450.     p = (struct key *)malloc(sizeof(struct key));
  451.     if (p != NULL) {
  452.         p->id = id;
  453.         p->key = key;
  454.         p->value = value;
  455.         PyThread_acquire_lock(keymutex, 1);
  456.         p->next = keyhead;
  457.         keyhead = p;
  458.         PyThread_release_lock(keymutex);
  459.     }
  460.     return p;
  461. }
  462.  
  463. int PyThread_create_key(void)
  464. {
  465.     if (keymutex == NULL)
  466.         keymutex = PyThread_allocate_lock();
  467.     return ++nkeys;
  468. }
  469.  
  470. void PyThread_delete_key(int key)
  471. {
  472.     struct key *p, **q;
  473.     PyThread_acquire_lock(keymutex, 1);
  474.     q = &keyhead;
  475.     while ((p = *q) != NULL) {
  476.         if (p->key == key) {
  477.             *q = p->next;
  478.             free((void *)p);
  479.             /* NB This does *not* free p->value! */
  480.         }
  481.         else
  482.             q = &p->next;
  483.     }
  484.     PyThread_release_lock(keymutex);
  485. }
  486.  
  487. int PyThread_set_key_value(int key, void *value)
  488. {
  489.     struct key *p = find_key(key, value);
  490.     if (p == NULL)
  491.         return -1;
  492.     else
  493.         return 0;
  494. }
  495.  
  496. void *PyThread_get_key_value(int key)
  497. {
  498.     struct key *p = find_key(key, NULL);
  499.     if (p == NULL)
  500.         return NULL;
  501.     else
  502.         return p->value;
  503. }
  504.