Add dl infrastructure for an optional sushiv_atexit()
[xiph/unicode.git] / sushivision / main.c
blob02cedaea2c858c34272d4384c17c6738377e3153
1 /*
3 * sushivision copyright (C) 2006-2007 Monty <monty@xiph.org>
5 * sushivision is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * sushivision is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with sushivision; see the file COPYING. If not, write to the
17 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define _GNU_SOURCE
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <math.h>
28 #include <signal.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <gtk/gtk.h>
32 #include <cairo-ft.h>
33 #include <pthread.h>
34 #include <dlfcn.h>
35 #include "internal.h"
38 static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
39 static pthread_cond_t mc = PTHREAD_COND_INITIALIZER;
40 sig_atomic_t _sushiv_exiting=0;
41 static int wake_pending = 0;
42 static int num_threads;
44 static int instances=0;
45 static sushiv_instance_t **instance_list;
47 void _sushiv_clean_exit(int sig){
48 _sushiv_exiting = 1;
49 _sushiv_wake_workers();
51 //signal(sig,SIG_IGN);
52 if(sig!=SIGINT)
53 fprintf(stderr,
54 "\nTrapped signal %d; exiting!\n",sig);
56 gtk_main_quit();
59 static int num_proccies(){
60 FILE *f = fopen("/proc/cpuinfo","r");
61 char * line = NULL;
62 size_t len = 0;
63 ssize_t read;
64 int num=1,arg;
66 if (f == NULL) return 1;
67 while ((read = getline(&line, &len, f)) != -1) {
68 if(sscanf(line,"processor : %d",&arg)==1)
69 if(arg+1>num)num=arg+1;
71 if (line)
72 free(line);
74 fprintf(stderr,"Number of processors: %d\n",num);
75 fclose(f);
76 return num;
79 void _sushiv_wake_workers(){
80 if(instances){
81 pthread_mutex_lock(&m);
82 wake_pending = num_threads;
83 pthread_cond_broadcast(&mc);
84 pthread_mutex_unlock(&m);
88 void _maintain_cache(sushiv_panel_t *p, _sushiv_compute_cache *c, int w){
90 /* toplevel initialization */
91 if(c->fout == 0){
92 int i,j;
94 /* determine which functions are actually needed */
95 c->call = calloc(p->sushi->functions,sizeof(*c->call));
96 c->fout = calloc(p->sushi->functions,sizeof(*c->fout));
97 for(i=0;i<p->objectives;i++){
98 sushiv_objective_t *o = p->objective_list[i].o;
99 for(j=0;j<o->outputs;j++)
100 c->call[o->function_map[j]]=
101 p->sushi->function_list[o->function_map[j]]->callback;
105 /* once to begin, as well as anytime the data width changes */
106 if(c->storage_width < w){
107 int i;
108 c->storage_width = w;
110 for(i=0;i<p->sushi->functions;i++){
111 if(c->call[i]){
112 if(c->fout[i])free(c->fout[i]);
113 c->fout[i] = malloc(w * p->sushi->function_list[i]->outputs *
114 sizeof(**c->fout));
120 static void *worker_thread(void *dummy){
121 /* set up temporary working space for function rendering; this saves
122 continuously recreating it in the loop below */
123 _sushiv_compute_cache **c; // [instance][panel]
124 int i,j;
126 c = calloc(instances,sizeof(*c));
127 for(j=0;j<instances;j++){
128 sushiv_instance_t *s = instance_list[j];
129 c[j] = calloc(s->panels,sizeof(**c));
132 while(1){
133 if(_sushiv_exiting)break;
135 // look for work
137 int flag=0;
138 // by instance
139 for(j=0;j<instances;j++){
140 sushiv_instance_t *s = instance_list[j];
142 for(i=0;i<s->panels;i++){
143 sushiv_panel_t *p = s->panel_list[i];
145 if(_sushiv_exiting)break;
147 // pending remap work?
148 gdk_threads_enter();
149 if(p->private->maps_dirty && !p->private->maps_rendering){
150 p->private->maps_dirty = 0;
151 p->private->maps_rendering = 1;
152 flag = 1;
154 gdk_threads_leave ();
155 p->private->map_redraw(p);
156 gdk_threads_enter ();
158 p->private->maps_rendering = 0;
161 // pending legend work?
162 if(p->private->legend_dirty && !p->private->legend_rendering){
163 p->private->legend_dirty = 0;
164 p->private->legend_rendering = 1;
165 flag = 1;
167 gdk_threads_leave ();
168 p->private->legend_redraw(p);
169 gdk_threads_enter ();
171 p->private->legend_rendering = 0;
173 gdk_threads_leave ();
175 // pending computation work?
176 flag |= _sushiv_panel_cooperative_compute(s->panel_list[i],
177 &c[j][i]);
180 if(flag==1)continue;
183 // nothing to do, wait
184 pthread_mutex_lock(&m);
185 if(!wake_pending)
186 pthread_cond_wait(&mc,&m);
187 else
188 wake_pending--;
189 pthread_mutex_unlock(&m);
192 pthread_mutex_unlock(&m);
193 return 0;
196 static char * gtkrc_string(){
198 return "";
201 static void sushiv_realize_instance(sushiv_instance_t *s){
202 int i;
203 for(i=0;i<s->panels;i++)
204 _sushiv_realize_panel(s->panel_list[i]);
205 for(i=0;i<s->panels;i++)
206 s->panel_list[i]->private->request_compute(s->panel_list[i]);
209 static void sushiv_realize_all(void){
210 int i;
211 for(i=0;i<instances;i++)
212 sushiv_realize_instance(instance_list[i]);
215 /* externally visible interface */
217 sushiv_instance_t *sushiv_new_instance(void) {
218 sushiv_instance_t *ret=calloc(1,sizeof(*ret));
219 ret->private = calloc(1,sizeof(*ret->private));
221 if(instances){
222 instance_list = realloc(instance_list,(instances+1)*sizeof(*instance_list));
223 }else{
224 instance_list = malloc((instances+1)*sizeof(*instance_list));
226 instance_list[instances] = ret;
227 instances++;
229 return ret;
232 int main (int argc, char *argv[]){
233 int ret;
235 num_threads = num_proccies();
237 gtk_init (&argc, &argv);
238 g_thread_init (NULL);
240 gtk_mutex_fixup();
241 gdk_threads_init ();
242 gtk_rc_parse_string(gtkrc_string());
243 gtk_rc_add_default_file("sushi-gtkrc");
245 ret = sushiv_submain(argc,argv);
246 if(ret)return ret;
248 sushiv_realize_all();
251 pthread_t dummy;
252 int threads = num_threads;
253 while(threads--)
254 pthread_create(&dummy, NULL, &worker_thread,NULL);
257 signal(SIGINT,_sushiv_clean_exit);
258 //signal(SIGSEGV,_sushiv_clean_exit);
260 gtk_button3_fixup();
261 gtk_main ();
264 int (*optional_exit)(void) = dlsym(RTLD_DEFAULT, "sushiv_atexit");
265 if(optional_exit)
266 return optional_exit();
269 return 0;