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