Pass new arguments (suspend/inherit) to the server.
[wine] / ipc / dde_mem.c
1 /***************************************************************************
2  * Copyright 1995, Technion, Israel Institute of Technology
3  * Electrical Eng, Software Lab.
4  * Author:    Michael Veksler.
5  ***************************************************************************
6  * File:      dde_mem.c
7  * Purpose :  shared DDE memory functionality for DDE
8  ***************************************************************************
9  */
10 #ifdef CONFIG_IPC
11
12 #include <assert.h>
13 #include "debug.h"
14 #include "ldt.h"
15 #include "shm_main_blk.h"
16 #include "shm_fragment.h"
17 #include "shm_semaph.h"
18 #include "dde_mem.h"
19 #include "bit_array.h"
20
21 #define SEGPTR2HANDLE_INFO(sptr) ( (struct handle_info*)PTR_SEG_TO_LIN(sptr) )
22
23 #define HINFO2DATAPTR(h_info_ptr) ( (void*) ( (char*)h_info_ptr +           \
24                                              sizeof(struct handle_info) ) )
25 #define DDE_MEM_IDX(handle) ((handle)& 0x7fff)
26 #define DDE_MEM_HANDLE(idx) ((idx) | 0x8000)
27 #define DDE_MEM_INFO(handle) (main_block->handles[ DDE_MEM_IDX(handle) ])
28 /* List of shared handles.
29  * This entry resides on the shared memory, the data comes right
30  * after the `handle_info'.
31  * The entry is on the same block as the actual data.
32  * The `next' field gives relative reference (relative to the start of
33  * the blcok.
34  */
35 struct handle_info {
36         WORD lock_count;
37         WORD flags;
38         int size;               /* size of the data (net)*/
39 };
40
41 static bit_array free_handles;
42 int debug_last_handle_size= 0;  /* for debugging purpose only */
43
44
45 /* locate_handle:
46  *   locate a shared memory handle.
47  * Application:
48  *   The handle is first searched for in attached blocks.
49  *   At the beginning, only blocks owned by this process are
50  *   attached.
51  *   If a handle is not found, new blocks are attached.
52  * Arguments:
53  *   h    - the handle.
54  * RETURN: pointer to handle info.
55  */
56 static struct handle_info *locate_handle(HGLOBAL16 h, struct local_shm_map *map)
57 {
58   struct shm_block *block;
59   
60   TRACE(global,"shm: (0x%04x)\n", h);
61
62
63   if (SampleBit( &free_handles, DDE_MEM_IDX(h)) == 0) {
64      TRACE(global, "shm: return NULL\n");
65      return NULL;                  /* free!!! */
66   }
67   
68   block= shm_locate_block(DDE_MEM_INFO(h).shmid, map);
69   if (block == NULL) {
70       /* nothing found */
71       TRACE(global, "shm: return NULL\n");
72       return NULL;
73   }
74
75   return (struct handle_info *) REL2PTR(block, DDE_MEM_INFO(h).rel);
76   
77 }
78
79 /* dde_alloc_handle: allocate shared DDE handle */
80 static HGLOBAL16 dde_alloc_handle()
81 {
82   int bit_nr;
83
84   bit_nr= AllocateBit( &free_handles);
85
86   if (bit_nr != -1)
87      return DDE_MEM_HANDLE(bit_nr);
88
89   TRACE(global,"dde_alloc_handle: no free DDE handle found\n");
90   return 0;
91 }
92 /**********************************************************************
93  *                                      DDE_malloc
94  */
95 void *
96 DDE_malloc(unsigned int flags, unsigned long size, SHMDATA *shmdata)
97 {
98     int shmid;
99     struct shm_block *block;
100     struct handle_info *h_info;
101     struct local_shm_map *curr;
102     HGLOBAL16 handle;
103     
104     TRACE(global,"DDE_malloc flags %4X, size %ld\n", flags, size);
105     DDE_IPC_init();             /* make sure main shm block allocated */ 
106
107     shm_write_wait(main_block->proc[curr_proc_idx].sem);
108
109     /* Try to find fragment big enough for `size' */
110     /* iterate through all local shm blocks, and try to allocate
111        the fragment */
112
113     h_info= NULL;
114     for (curr=  shm_map ; curr != NULL ; curr= curr->next) {
115        if (curr->proc_idx == curr_proc_idx) {
116           h_info= (struct handle_info *)
117              shm_FragPtrAlloc(curr->ptr, size+sizeof(struct handle_info));
118           if (h_info!=NULL) {
119              shmid= curr->shm_id;
120              break;
121           }
122        }
123     }
124
125     if (h_info == NULL) {
126        
127        block= shm_create_block(0, size+sizeof(struct handle_info), &shmid);
128        if (block==NULL) {
129           shm_write_signal(main_block->proc[curr_proc_idx].sem);
130           return 0;
131        }
132        /* put the new block in the linked list */
133        block->next_shm_id= main_block->proc[curr_proc_idx].shmid;
134        main_block->proc[curr_proc_idx].shmid= shmid;
135        h_info= (struct handle_info *)
136           shm_FragPtrAlloc(block, size+sizeof(struct handle_info));
137        if (h_info==NULL) {
138           ERR(global,"BUG! unallocated fragment\n");
139           shm_write_signal(main_block->proc[curr_proc_idx].sem);
140           return 0;
141        }
142     } else {
143        block= curr->ptr;
144     }
145
146     /* Here we have an allocated fragment */
147     h_info->flags= flags;
148     h_info->lock_count= 0;
149     h_info->size= size;
150     handle= dde_alloc_handle();
151     
152     if (handle) {
153        TRACE(global, "returning handle=0x%4x, ptr=0x%08lx\n",
154                       (int)handle, (long) HINFO2DATAPTR(h_info));
155        DDE_MEM_INFO(handle).rel=  PTR2REL(block, h_info);
156        DDE_MEM_INFO(handle).shmid= shmid;
157     }
158     else
159        WARN(global, "failed\n");
160
161     shm_write_signal(main_block->proc[curr_proc_idx].sem);
162     
163     shmdata->handle= handle;
164     return (char *)HINFO2DATAPTR(h_info);
165 }
166
167 HGLOBAL16 DDE_GlobalFree(HGLOBAL16 h)
168 {
169   struct handle_info *h_info;
170   int handle_index= h & 0x7fff;
171   struct local_shm_map map;
172
173   TRACE(global,"(0x%04x)\n",h);
174
175   if (h==0)
176      return 0;
177
178   h_info= locate_handle(h, &map);
179   if (h_info == NULL)
180       return h;
181
182   shm_write_wait(main_block->proc[map.proc_idx].sem);
183
184   shm_FragPtrFree(map.ptr, (struct shm_fragment *) h_info);
185
186   AssignBit( &free_handles, handle_index, 0);
187   
188   /* FIXME: must free the shm block some day. */
189   shm_write_signal(main_block->proc[map.proc_idx].sem);
190   return 0;
191 }
192
193 WORD DDE_SyncHandle(HGLOBAL16 handle, WORD sel)
194     
195 {
196     struct handle_info *h_info;
197     void *local_ptr;
198     ldt_entry entry;
199     
200     h_info= locate_handle(handle, NULL);
201     local_ptr= (void *)GET_SEL_BASE(sel);
202
203     
204     if (h_info == NULL)
205         return 0;
206     
207     if (local_ptr == (void *) HINFO2DATAPTR(h_info))
208         return sel;
209
210     /* need syncronization ! */
211     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
212     entry.base= (unsigned long) HINFO2DATAPTR(h_info);
213     LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
214
215     return sel;
216 }
217
218 /*
219  * DDE_AttachHandle:
220  * Attach shm memory (The data must not be already attached).
221  * Parameters:
222  *   handle - the memory to attach.
223  *   segptr - in not null, return SEGPTR to the same block.
224  * return value:
225  *   32 bit pointer to the memory.
226  */
227
228 void *DDE_AttachHandle(HGLOBAL16 handle, SEGPTR *segptr)
229 {
230   struct handle_info *h_info;
231   SHMDATA shmdata;
232   void *ptr;
233   HGLOBAL16 hOwner = GetCurrentPDB16();
234
235   assert(is_dde_handle(handle));
236   if (segptr != NULL)
237       *segptr=0;
238
239   TRACE(global,"(%04x)\n",handle);
240   h_info=locate_handle(handle, NULL);
241
242   if (h_info == NULL) 
243       return NULL;
244
245   if ( !(h_info->flags & GMEM_DDESHARE) ) {
246       ERR(global,"Corrupted memory handle info\n");
247       return NULL;
248   }
249   
250   TRACE(global,"h_info=%06lx\n",(long)h_info);
251
252   shmdata.handle= handle;
253   shmdata.shmid= DDE_MEM_INFO(handle).shmid;
254
255   ptr= HINFO2DATAPTR(h_info);
256   /* Allocate the selector(s) */
257   if (! GLOBAL_CreateBlock( h_info->flags, ptr, h_info->size, hOwner,
258                             FALSE, FALSE, FALSE, &shmdata)) 
259       return NULL;
260
261   if (segptr != NULL) 
262       *segptr= (SEGPTR)MAKELONG( 0, shmdata.sel);
263
264   if (TRACE_ON(dde))
265       debug_last_handle_size= h_info->size;
266
267   TRACE(global,"DDE_AttachHandle returns ptr=0x%08lx\n", (long)ptr);
268
269   return (LPSTR)ptr;
270
271 }
272
273 void DDE_mem_init()
274 {
275   int nr_of_bits;
276
277   shm_init();
278   
279   nr_of_bits= BITS_PER_BYTE * sizeof(main_block->free_handles);
280   AssembleArray( &free_handles, main_block->free_handles, nr_of_bits);
281 }
282
283 #endif  /* CONFIG_IPC */