source: trunk/sys/libpthread/pthread_condition.c @ 234

Last change on this file since 234 was 1, checked in by alain, 8 years ago

First import

File size: 4.6 KB
Line 
1/*
2 * pthread.c -  conditions variables related functions
3 *
4 * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless
5 * Copyright (c) 2011,2012 UPMC Sorbonne Universites
6 *
7 * This file is part of ALMOS.
8 *
9 * ALMOS is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2.0 of the License.
12 *
13 * ALMOS is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ALMOS; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <sys/types.h>
24#include <errno.h>
25#include <semaphore.h>
26#include <pthread.h>
27#include <sys/syscall.h>
28#include <cpu-syscall.h>
29
30typedef enum
31{
32        CV_INIT,
33        CV_WAIT,
34        CV_SIGNAL,
35        CV_BROADCAST,
36        CV_DESTROY
37} cv_operation_t;
38
39static int __sys_cond_var(void *sysid, int operation, sem_t *sem)
40{
41        register int retval;
42 
43        retval = (int)cpu_syscall(sysid,(void*)operation,(void*)sem,NULL,SYS_COND_VAR);
44        return retval;
45}
46
47int pthread_condattr_init(pthread_condattr_t *attr)
48{
49        if(attr == NULL)
50                return EINVAL;
51
52        attr->scope = PTHREAD_PROCESS_PRIVATE;
53        return 0;
54}
55
56int pthread_condattr_destroy(pthread_condattr_t *attr)
57{
58        if(attr == NULL)
59                return EINVAL;
60
61        attr->scope = -1;
62        return 0;
63}
64
65int pthread_condattr_getpshared(pthread_condattr_t *attr, int *scope)
66{
67        if((attr == NULL) || (attr->scope < 0) || (scope == NULL))
68                return EINVAL;
69
70        *scope = attr->scope;
71        return 0;
72}
73
74int pthread_condattr_setpshared(pthread_condattr_t *attr, int scope)
75{
76        if((attr == NULL) || ((scope != PTHREAD_PROCESS_PRIVATE) && (scope != PTHREAD_PROCESS_SHARED)))
77                return EINVAL;
78
79        attr->scope = scope;
80        return 0;
81}
82
83int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
84{
85        int err;
86
87        if(cond == NULL) return EINVAL;
88
89        if((cond_attr != NULL) && (cond_attr->scope == PTHREAD_PROCESS_SHARED))
90        {
91                cond->scope = PTHREAD_PROCESS_SHARED;
92                return __sys_cond_var(&cond->sysid, CV_INIT, NULL);
93        }
94
95        cond->scope = PTHREAD_PROCESS_PRIVATE;
96
97        err = pthread_spin_init(&cond->lock, 0);
98
99        if(err) return err;
100
101        cond->count = 0;
102        return 0;
103}
104
105int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
106{
107        register __pthread_tls_t *tls;
108        register struct __shared_s *shared;
109        int err;
110
111        if((cond == NULL) || (mutex == NULL) || (mutex->attr.scope != cond->scope))
112                return EINVAL;
113
114        if(cond->scope == PTHREAD_PROCESS_SHARED)
115                return __sys_cond_var(&cond->sysid, CV_WAIT, &mutex->sem);
116
117        if(cond->count == 0)
118                list_root_init(&cond->queue);
119 
120        cond->count ++;
121
122        tls = cpu_get_tls();
123        shared = (struct __shared_s*)__pthread_tls_get(tls, __PT_TLS_SHARED);
124
125        list_add_last(&cond->queue, &shared->list);
126
127        (void)pthread_mutex_unlock(mutex);
128
129        /* TODO: compute syscall return value (signals treatment) */
130        (void)cpu_syscall(NULL, NULL, NULL, NULL, SYS_SLEEP);
131 
132        err = pthread_mutex_lock(mutex);
133        return err;
134}
135
136int pthread_cond_signal(pthread_cond_t *cond)
137{
138        struct __shared_s *next;
139        int err;
140
141        if(cond == NULL) return EINVAL;
142
143        if(cond->scope == PTHREAD_PROCESS_SHARED)
144                return __sys_cond_var(&cond->sysid, CV_SIGNAL, NULL);
145
146        if(cond->count == 0)
147                return 0;
148
149        next = list_first(&cond->queue, struct __shared_s, list);
150        list_unlink(&next->list);
151        cond->count --;
152
153        (void)cpu_syscall((void*)next->tid, NULL, NULL, NULL, SYS_WAKEUP);
154        return 0;
155}
156
157int pthread_cond_broadcast(pthread_cond_t *cond)
158{
159        struct list_entry root;
160        struct list_entry *list;
161        struct __shared_s *next;
162        uint_t count;
163        uint_t i;
164        int err = 0;
165 
166        if(cond == NULL) return EINVAL;
167 
168        if(cond->scope == PTHREAD_PROCESS_SHARED)
169                return __sys_cond_var(&cond->sysid, CV_BROADCAST, NULL);
170
171        if(cond->count == 0)
172        {
173                return 0;
174        }
175
176        count       = cond->count;
177        cond->count = 0;
178        list_replace(&cond->queue, &root);
179
180        uint_t tbl[100];
181
182        i = 0;
183 
184        while(count)
185        {
186                list_foreach_forward(&root, list)
187                {
188                        next   = list_element(list, struct __shared_s, list);
189                        list_unlink(&next->list);
190                        tbl[i] = next->tid;
191                        count --;
192                        i++;
193
194                        if(i == 100)
195                        {
196                                i = 0;
197                                (void)cpu_syscall((void*)tbl[0], (void*)&tbl[0], (void*)100, NULL, SYS_WAKEUP);
198                        }
199                }
200        }
201
202        if(i != 0)
203                (void)cpu_syscall((void*)tbl[0], (void*)&tbl[0], (void*)i, NULL, SYS_WAKEUP);
204   
205        return err;
206}
207
208int pthread_cond_destroy(pthread_cond_t *cond)
209{
210        int err = 0;
211 
212        if(cond == NULL)
213                return EINVAL;
214
215        if(cond->scope == PTHREAD_PROCESS_SHARED)
216                return __sys_cond_var(&cond->sysid, CV_DESTROY, NULL);
217
218        if(cond->count != 0)
219                err = EBUSY;
220
221        return err;
222}
Note: See TracBrowser for help on using the repository browser.