Added more batch functionality, including the CALL GOTO and SHIFT
[wine] / ipc / shm_main_blk.c
1 /***************************************************************************
2  * Copyright 1995, Technion, Israel Institute of Technology
3  * Electrical Eng, Software Lab.
4  * Author:    Michael Veksler.
5  ***************************************************************************
6  * File:      shm_main_blk.c
7  * Purpose:   Main Wine's shared memory block
8  ***************************************************************************
9  */
10 #ifdef CONFIG_IPC
11
12 #include <sys/types.h>
13 #include <sys/sem.h>
14 #include <time.h>
15 #include <assert.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <signal.h>
19 #include "debugtools.h"
20 #include "shm_fragment.h"
21 #include "shm_block.h"
22 #include "shm_main_blk.h"
23 #include "shm_semaph.h"
24
25 DEFAULT_DEBUG_CHANNEL(shm)
26
27 #define WineKey (   'W'+((int)'i'<<8)+((int)'n'<<16)+((int)'e'<<24)  )
28 #define SHM_KEY_RANGE 8
29
30 /* main block (set during initialization) */
31 struct shm_main_block *main_block=NULL;
32 static char *shm_header="Wine - Windows emulator DDE mechanism";
33 static int main_shm_id;
34
35 static void shm_main_refresh();
36
37 /* for debugging only */
38 static void print_perm(struct ipc_perm *perm)
39 {
40   printf("Permission:\n");
41 /* FIXME: not portable
42   printf("\tKey=%d,   mode=%03o,   sequence #=%d\n",
43          (int)perm->key,perm->mode, perm->seq);
44 */
45   printf("\towner: uid=%d, gid=%d ;"  ,perm->uid, perm->gid);
46   printf("  creator: uid=%d, gid=%d\n",perm->cuid,perm->cgid);
47 }
48
49 /* for debugging only */
50 /* print_shm_info: print shared memory descriptor info */
51 static void print_shm_info(int shm_id)
52 {
53   struct shmid_ds ds;
54   shmctl(shm_id, IPC_STAT, &ds );
55
56   printf("shm_id=%d, Size=0x%08x , Number of attaches=%d\n",
57          shm_id, ds.shm_segsz, (int)ds.shm_nattch);
58   if (ds.shm_atime)
59      printf("Last attach=%s",ctime(&ds.shm_atime));
60   if (ds.shm_dtime)
61      printf("Last detach=%s",ctime(&ds.shm_dtime));
62   printf("Last change=%s",ctime(&ds.shm_ctime));
63   printf("pid: creator=%d, last operator=%d\n",
64          (int)ds.shm_cpid,(int)ds.shm_lpid);
65   print_perm( &ds.shm_perm);
66
67 }
68
69 int proc_exist(pid_t pid)
70 {
71   if ( kill(pid,0) == 0)           /* dummy signal to test existence */
72      return 1;
73   else if (errno==ESRCH)           /* "no such process" */
74      return 0;
75   else
76      return 1;
77 }
78
79 /* setup a new main shm block (only construct a shm block object). */
80 static void shm_setup_main_block()
81 {
82   TRACE("creating data structure\n");
83   main_block->build_lock=1;
84   strcpy(main_block->magic, shm_header);
85
86   shm_setup_block(&main_block->block,sizeof(*main_block),SHM_MINBLOCK);
87
88   dde_proc_init(main_block->proc);
89   ATOM_GlobalInit();
90   shm_sem_init(&main_block->sem);
91
92   /* main block set and data structure is stable now */
93   main_block->build_lock=0;
94 }
95
96 /* Delete everything related to main_block */
97 void shm_delete_all(int shmid)
98 {
99   int proc_idx;
100
101   if (shmid == -1) 
102     shmid= main_shm_id;
103   
104   shmctl( shmid, IPC_RMID, NULL);
105   
106   for (proc_idx= 0 ; proc_idx < DDE_PROCS ; proc_idx++)
107      dde_proc_done( &main_block->proc[proc_idx] );
108   
109   shm_sem_done(&main_block->sem);
110   shmdt( (void *) main_block);
111   main_block= NULL;
112 }
113
114 int DDE_no_of_attached()
115 {
116   struct shmid_ds shm_info;
117   
118   if (shmctl(main_shm_id, IPC_STAT, &shm_info) == -1)
119     return -1;
120
121   return shm_info.shm_nattch;
122 }
123 /*
124 ** Test if shm_id is MainBlock and attach it (if it is),
125 ** Return 1 if ok, 0 otherwise.
126 */
127 static int attach_MainBlock(int shm_id)
128 {
129   struct shmid_ds shm_info;
130
131   if (shmctl(shm_id, IPC_STAT, &shm_info) == -1)
132      return 0;
133
134   /* Make sure we don't work on somebody else's block */
135   if (shm_info.shm_perm.cuid != getuid()) { /* creator is not me */
136      WARN("Creator is not me!\n");
137      return 0;
138   }
139
140   TRACE("shared memory exist, attaching anywhere\n");
141   main_block=(struct shm_main_block *)shmat(shm_id, 0, 0);
142   if ( (int)main_block==-1) {
143      WARN("Attach failed\n");
144      return 0;
145   }
146
147   if (strcmp(main_block->magic, shm_header) != 0) {
148      TRACE("Detaching, wrong magic\n");
149      shmdt((void *)main_block);
150      return 0;
151   }
152
153   if (TRACE_ON(shm))
154      print_shm_info(shm_id);
155
156   /* Is it an old unused block ? */
157   if (shm_info.shm_nattch == 0) {
158      TRACE("No attaches, deleting old data\n");
159      shm_delete_all(shm_id);
160      return 0;
161   }
162
163   /* Wait for data structure to stabilize */
164   while (main_block->build_lock)
165      usleep(10000);
166
167   main_shm_id= shm_id;
168
169   shm_main_refresh();
170   return 1;
171 }
172
173 /* (Function used by the constructor)
174  * Try to get existing shared memory with key="Wine", size=SHM_MINBLOCK
175  * complete user permission.
176  * If such block is found - return true (1),  else return false (0)
177  */
178 static int shm_locate_MainBlock(key_t shm_key)
179 {
180     int shm_id;                 /* Descriptor to this shared memory */
181     int i;
182
183     TRACE("trying to attach, key=0x%x\n",
184                 shm_key);
185     for (i=0 ; i < SHM_KEY_RANGE ; i++) {
186        TRACE("iteration=%d\n", i);
187
188        shm_id= shmget ( shm_key+i, SHM_MINBLOCK ,0700);
189
190        if (shm_id != -1) {
191          if ( attach_MainBlock(shm_id) ) {
192            return 1;               /* success! */
193          }
194        } else {
195           switch(errno) {
196 #ifdef EIDRM
197             case EIDRM:            /* segment destroyed */
198 #endif
199             case EACCES:           /* no user permision */
200               break;
201
202             case ENOMEM:           /* no free memory */
203             case ENOENT:           /* this key does not exist */
204             default :
205               WARN("shmget failed, errno=%d, %s\n",
206                      errno, strerror(errno) );
207               return 0;            /* Failed */
208           }
209        } /* if .. else */
210     } /* for */
211     return 0;
212 }
213
214 /* (Function used by the constructor)
215  * Try to allocate new shared memory with key="Wine", size=SHM_MINBLOCK
216  * with complete user permission.
217  * If allocation succeeds - return true (1),  else return false (0)
218  */
219 static int shm_create_MainBlock(key_t MainShmKey)
220 {
221   int shm_id;
222   int flags= 0700 | IPC_CREAT | IPC_EXCL;
223   int i;
224
225   TRACE("creating shared memory\n");
226
227   /* try to allocate shared memory with key="Wine", size=SHM_MINBLOCK, */
228   /* complete user permission */
229   for (i=0 ; i < SHM_KEY_RANGE ; i++) {
230      shm_id= shmget ( (key_t) MainShmKey, SHM_MINBLOCK, flags);
231      if (shm_id != -1)
232         break;
233   }
234   if (shm_id == -1) {
235      WARN("failed to create shared memory\n");
236      return 0;
237   }
238   TRACE("shared memory created, attaching\n");
239   main_block=(struct shm_main_block*) shmat(shm_id, 0,0);
240   if (TRACE_ON(shm))
241      print_shm_info(shm_id);
242   main_shm_id= shm_id;
243   shm_setup_main_block();
244   dde_wnd_setup();
245   return 1;
246
247 }
248
249 /* link to the dde shared memory block */
250 /* RETURN: 0 on success, non zero on failure */
251 int shm_init(void)
252 {
253   if ( !shm_locate_MainBlock(WineKey)
254        && !shm_create_MainBlock(WineKey)) { 
255      ERR("Failed to init main shm block\n");
256      exit(1);
257   }
258
259   dde_proc_add(main_block->proc);
260   return 0;
261 }
262
263 static void shm_main_refresh()
264 {
265   int proc_idx;
266   
267   for (proc_idx= 0 ; proc_idx < DDE_PROCS ; proc_idx++)
268      dde_proc_refresh( &main_block->proc[proc_idx] );
269 }
270
271 #endif  /* CONFIG_IPC */