Advertisement
Guest User

sheepthreads.c

a guest
Sep 13th, 2012
310
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.01 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement