daily pastebin goal
62%
SHARE
TWEET

sheepthreads.c

a guest Sep 13th, 2012 100 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  *  sheepthreads.c - Minimal pthreads implementation (libpthreads doesn't
  3.  *                   like nonstandard stacks)
  4.  *
  5.  *  SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
  6.  *
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  */
  21.  
  22. /*
  23.  *  NOTES:
  24.  *   - pthread_cancel() kills the thread immediately
  25.  *   - Semaphores are VERY restricted: the only supported use is to have one
  26.  *     thread sem_wait() on the semaphore while other threads sem_post() it
  27.  *     (i.e. to use the semaphore as a signal)
  28.  */
  29.  
  30. #include <sys/types.h>
  31. #include <sys/wait.h>
  32. #include <stdlib.h>
  33. #include <errno.h>
  34. #include <unistd.h>
  35. #include <signal.h>
  36. #include <pthread.h>
  37.  
  38.  
  39. /* Thread stack size */
  40. #define STACK_SIZE 65536
  41.  
  42. /* From asm_linux.S */
  43. extern int atomic_add(int *var, int add);
  44. extern int atomic_and(int *var, int and);
  45. extern int atomic_or(int *var, int or);
  46. extern int test_and_set(int *var, int val);
  47.  
  48. /* Linux kernel calls */
  49. extern int __clone(int (*fn)(void *), void *, int, void *);
  50.  
  51. /* libc no longer provides struct _pthread_fastlock in pthread.h */
  52. struct fastlock {
  53.         int status;
  54.         int spinlock;
  55. };
  56.  
  57. typedef struct {
  58.         struct fastlock sem_lock;
  59.         int sem_value;
  60.         int sem_waiting;
  61. } sem_t;
  62.  
  63. #define SEM_VALUE_MAX 64
  64.  
  65. /* Wait for "clone" children only (Linux 2.4+ specific) */
  66. #ifndef __WCLONE
  67. #define __WCLONE 0
  68. #endif
  69.  
  70.  
  71. /*
  72.  *  Return pthread ID of self
  73.  */
  74.  
  75. pthread_t pthread_self(void)
  76. {
  77.         return getpid();
  78. }
  79.  
  80.  
  81. /*
  82.  *  Test whether two pthread IDs are equal
  83.  */
  84.  
  85. int pthread_equal(pthread_t t1, pthread_t t2)
  86. {
  87.         return t1 == t2;
  88. }
  89.  
  90.  
  91. /*
  92.  *  Send signal to thread
  93.  */
  94.  
  95. int pthread_kill(pthread_t thread, int sig)
  96. {
  97.         if (kill(thread, sig) == -1)
  98.                 return errno;
  99.         else
  100.                 return 0;
  101. }
  102.  
  103.  
  104. /*
  105.  *  Create pthread
  106.  */
  107.  
  108. struct new_thread {
  109.         void *(*fn)(void *);
  110.         void *arg;
  111. };
  112.  
  113. static int start_thread(void *arg)
  114. {
  115.         struct new_thread *nt = (struct new_thread *)arg;
  116.         nt->fn(nt->arg);
  117.         return 0;
  118. }
  119.  
  120. int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
  121. {
  122.         struct new_thread *nt;
  123.         void *stack;
  124.         int pid;
  125.  
  126.         nt = (struct new_thread *)malloc(sizeof(struct new_thread));
  127.         nt->fn = start_routine;
  128.         nt->arg = arg;
  129.         stack = malloc(STACK_SIZE);
  130.  
  131.         pid = __clone(start_thread, (char *)stack + STACK_SIZE - 16, CLONE_VM | CLONE_FS | CLONE_FILES, nt);
  132.         if (pid == -1) {
  133.                 free(stack);
  134.                 free(nt);
  135.                 return errno;
  136.         } else {
  137.                 *thread = pid;
  138.                 return 0;
  139.         }
  140. }
  141.  
  142.  
  143. /*
  144.  *  Join pthread
  145.  */
  146.  
  147. int pthread_join(pthread_t thread, void **ret)
  148. {
  149.         do {
  150.                 if (waitpid(thread, NULL, __WCLONE) >= 0);
  151.                         break;
  152.         } while (errno == EINTR);
  153.         if (ret)
  154.                 *ret = NULL;
  155.         return 0;
  156. }
  157.  
  158.  
  159. /*
  160.  *  Cancel thread
  161.  */
  162.  
  163. int pthread_cancel(pthread_t thread)
  164. {
  165.         kill(thread, SIGINT);
  166.         return 0;
  167. }
  168.  
  169.  
  170. /*
  171.  *  Test for cancellation
  172.  */
  173.  
  174. void pthread_testcancel(void)
  175. {
  176. }
  177.  
  178.  
  179. /*
  180.  *  Spinlocks
  181.  */
  182.  
  183. /* For multiprocessor systems, we want to ensure all memory accesses
  184.    are completed before we reset a lock.  On other systems, we still
  185.    need to make sure that the compiler has flushed everything to memory.  */
  186. #define MEMORY_BARRIER() __asm__ __volatile__ ("sync" : : : "memory")
  187.  
  188. static void fastlock_init(struct fastlock *lock)
  189. {
  190.         lock->status = 0;
  191.         lock->spinlock = 0;
  192. }
  193.  
  194. static int fastlock_try_acquire(struct fastlock *lock)
  195. {
  196.         int res = EBUSY;
  197.         if (test_and_set(&lock->spinlock, 1) == 0) {
  198.                 if (lock->status == 0) {
  199.                         lock->status = 1;
  200.                         MEMORY_BARRIER();
  201.                         res = 0;
  202.                 }
  203.                 lock->spinlock = 0;
  204.         }
  205.         return res;
  206. }
  207.  
  208. static void fastlock_acquire(struct fastlock *lock)
  209. {
  210.         MEMORY_BARRIER();
  211.         while (test_and_set(&lock->spinlock, 1))
  212.                 usleep(0);
  213. }
  214.  
  215. static void fastlock_release(struct fastlock *lock)
  216. {
  217.         MEMORY_BARRIER();
  218.         lock->spinlock = 0;
  219.         __asm__ __volatile__ ("" : "=m" (lock->spinlock) : "m" (lock->spinlock));
  220. }
  221.  
  222.  
  223. /*
  224.  *  Initialize mutex
  225.  */
  226.  
  227. int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutex_attr)
  228. {
  229.         fastlock_init((struct fastlock *)mutex);
  230.         return 0;
  231. }
  232.  
  233.  
  234. /*
  235.  *  Destroy mutex
  236.  */
  237.  
  238. int pthread_mutex_destroy(pthread_mutex_t *mutex)
  239. {
  240.         return (((struct fastlock *)mutex)->status != 0) ? EBUSY : 0;
  241. }
  242.  
  243.  
  244. /*
  245.  *  Lock mutex
  246.  */
  247.  
  248. int pthread_mutex_lock(pthread_mutex_t *mutex)
  249. {
  250.         fastlock_acquire((struct fastlock *)mutex);
  251.         return 0;
  252. }
  253.  
  254.  
  255. /*
  256.  *  Try to lock mutex
  257.  */
  258.  
  259. int pthread_mutex_trylock(pthread_mutex_t *mutex)
  260. {
  261.         return fastlock_try_acquire((struct fastlock *)mutex);
  262. }
  263.  
  264.  
  265. /*
  266.  *  Unlock mutex
  267.  */
  268.  
  269. int pthread_mutex_unlock(pthread_mutex_t *mutex)
  270. {
  271.         fastlock_release((struct fastlock *)mutex);
  272.         return 0;
  273. }
  274.  
  275.  
  276. /*
  277.  *  Create mutex attribute
  278.  */
  279.  
  280. int pthread_mutexattr_init(pthread_mutexattr_t *attr)
  281. {
  282.         return 0;
  283. }
  284.  
  285.  
  286. /*
  287.  *  Destroy mutex attribute
  288.  */
  289.  
  290. int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
  291. {
  292.         return 0;
  293. }
  294.  
  295.  
  296. /*
  297.  *  Init semaphore
  298.  */
  299.  
  300. int sem_init(sem_t *sem, int pshared, unsigned int value)
  301. {
  302.         if (sem == NULL || value > SEM_VALUE_MAX) {
  303.                 errno = EINVAL;
  304.                 return -1;
  305.         }
  306.         if (pshared) {
  307.                 errno = ENOSYS;
  308.                 return -1;
  309.         }
  310.         fastlock_init(&sem->sem_lock);
  311.         sem->sem_value = value;
  312.         sem->sem_waiting = 0;
  313.         return 0;
  314. }
  315.  
  316.  
  317. /*
  318.  *  Delete remaphore
  319.  */
  320.  
  321. int sem_destroy(sem_t *sem)
  322. {
  323.         if (sem == NULL) {
  324.                 errno = EINVAL;
  325.                 return -1;
  326.         }
  327.         if (sem->sem_waiting) {
  328.                 errno = EBUSY;
  329.                 return -1;
  330.         }
  331.         sem->sem_value = 0;
  332.         sem->sem_waiting = 0;
  333.         return 0;
  334. }
  335.  
  336.  
  337. /*
  338.  *  Wait on semaphore
  339.  */
  340.  
  341. int sem_wait(sem_t *sem)
  342. {
  343.         if (sem == NULL) {
  344.                 errno = EINVAL;
  345.                 return -1;
  346.         }
  347.         fastlock_acquire(&sem->sem_lock);
  348.         if (sem->sem_value > 0) {
  349.                 sem->sem_value--;
  350.                 fastlock_release(&sem->sem_lock);
  351.                 return 0;
  352.         }
  353.         sem->sem_waiting++;
  354.         while (sem->sem_value == 0) {
  355.                 fastlock_release(&sem->sem_lock);
  356.                 usleep(0);
  357.                 fastlock_acquire(&sem->sem_lock);
  358.         }
  359.         sem->sem_value--;
  360.         fastlock_release(&sem->sem_lock);
  361.         return 0;
  362. }
  363.  
  364.  
  365. /*
  366.  *  Post semaphore
  367.  */
  368.  
  369. int sem_post(sem_t *sem)
  370. {
  371.         if (sem == NULL) {
  372.                 errno = EINVAL;
  373.                 return -1;
  374.         }
  375.         fastlock_acquire(&sem->sem_lock);
  376.         if (sem->sem_waiting)
  377.                 sem->sem_waiting--;
  378.         else {
  379.                 if (sem->sem_value >= SEM_VALUE_MAX) {
  380.                         errno = ERANGE;
  381.                         fastlock_release(&sem->sem_lock);
  382.                         return -1;
  383.                 }
  384.         }
  385.         sem->sem_value++;
  386.         fastlock_release(&sem->sem_lock);
  387.         return 0;
  388. }
  389.  
  390.  
  391. /*
  392.  *  Simple producer/consumer test program
  393.  */
  394.  
  395. #ifdef TEST
  396. #include <stdio.h>
  397.  
  398. static sem_t p_sem, c_sem;
  399. static int data = 0;
  400.  
  401. static void *producer_func(void *arg)
  402. {
  403.         int i, n = (int)arg;
  404.         for (i = 0; i < n; i++) {
  405.                 sem_wait(&p_sem);
  406.                 data++;
  407.                 sem_post(&c_sem);
  408.         }
  409.         return NULL;
  410. }
  411.  
  412. static void *consumer_func(void *arg)
  413. {
  414.         int i, n = (int)arg;
  415.         for (i = 0; i < n; i++) {
  416.                 sem_wait(&c_sem);
  417.                 printf("data: %d\n", data);
  418.                 sem_post(&p_sem);
  419.         }
  420.         sleep(1); // for testing pthread_join()
  421.         return NULL;
  422. }
  423.  
  424. int main(void)
  425. {
  426.         pthread_t producer_thread, consumer_thread;
  427.         static const int N = 5;
  428.  
  429.         if (sem_init(&c_sem, 0, 0) < 0)
  430.                 return 1;
  431.         if (sem_init(&p_sem, 0, 1) < 0)
  432.                 return 2;
  433.         if (pthread_create(&producer_thread, NULL, producer_func, (void *)N) != 0)
  434.                 return 3;
  435.         if (pthread_create(&consumer_thread, NULL, consumer_func, (void *)N) != 0)
  436.                 return 4;
  437.         pthread_join(producer_thread, NULL);
  438.         pthread_join(consumer_thread, NULL);
  439.         sem_destroy(&p_sem);
  440.         sem_destroy(&c_sem);
  441.         if (data != N)
  442.                 return 5;
  443.         return 0;
  444. }
  445. #endif
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top