Release 950216
[wine] / memory / linear.c
1 /*
2 static char RCSId[] = "$Id$";
3 static char Copyright[] = "Copyright  Robert J. Amstadt, 1994";
4 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include "prototypes.h"
9 #include "heap.h"
10 #include "segmem.h"
11
12 #ifdef HAVE_IPC
13 static key_t MemoryKeys[SHMSEG];        /* Keep track of keys were using */
14 static int   LinearInitialized = 0;
15 #endif
16
17 \f
18 #ifdef HAVE_IPC
19 /**********************************************************************
20  *                                      LinearFindSpace
21  */
22 int 
23 LinearFindSpace(int n_segments)
24 {
25     int i, n;
26     
27     if (!LinearInitialized)
28     {
29         memset(MemoryKeys, -1, sizeof(MemoryKeys));
30         return 0;
31     }
32
33     for (i = 0, n = 0; i < SHMSEG, n != n_segments; i++)
34     {
35         if (MemoryKeys[i] < 0)
36             n++;
37         else
38             n = 0;
39     }
40     
41     if (n != n_segments)
42         return -1;
43     else
44         return i - n;
45 }
46 #endif /* HAVE_IPC */
47 \f
48 /**********************************************************************
49  *                                      GlobalLinearLock
50  *
51  * OK, this is an evil beast.  We will do one of two things:
52  *
53  *      1. If the data item <= 64k, then just call GlobalLock().
54  *      2. If the data item > 64k, then map memory.
55  */
56 void *
57 GlobalLinearLock(unsigned int block)
58 {
59     GDESC *g, *g_first;
60     int loc_idx;
61     unsigned long addr;
62     int i;
63     
64     /******************************************************************
65      * Get GDESC for this block.
66      */
67     g_first = GlobalGetGDesc(block);
68     if (g_first == NULL)
69         return 0;
70
71     /******************************************************************
72      * Is block less then 64k in length?
73      */
74     if (g_first->sequence != 1 || g_first->length == 1)
75     {
76         return (void *) GlobalLock(block);
77     }
78
79     /******************************************************************
80      * If there is already a linear lock on this memory, then
81      * just return a pointer to it.
82      */
83     if (g_first->linear_count)
84     {
85         g_first->linear_count++;
86         return g_first->linear_addr;
87     }
88     
89     /******************************************************************
90      * No luck.  We need to do the linear mapping right now.
91      */
92 #ifdef HAVE_IPC
93     loc_idx = LinearFindSpace(g_first->length);
94     if (loc_idx < 0)
95         return NULL;
96     
97     addr = (unsigned long) SHM_RANGE_START + (0x10000 * loc_idx);
98     g = g_first;
99     for (i = loc_idx; 
100          i < loc_idx + g_first->length; 
101          i++, addr += 0x10000, g = g->next)
102     {
103         if ((MemoryKeys[i] = IPCCopySelector(g->handle >> __AHSHIFT,
104                                              addr, 0)) < 0)
105             return NULL;
106         g->linear_addr = (void *) addr;
107         g->linear_count = 1;
108     }
109 #endif /* HAVE_IPC */
110
111     return g_first->linear_addr;
112 }
113 \f
114 /**********************************************************************
115  *                                      GlobalLinearUnlock
116  *
117  */
118 unsigned int
119 GlobalLinearUnlock(unsigned int block)
120 {
121     GDESC *g, *g_first;
122     int loc_idx;
123     int i;
124     
125     /******************************************************************
126      * Get GDESC for this block.
127      */
128     g_first = GlobalGetGDesc(block);
129     if (g_first == NULL)
130         return block;
131
132     /******************************************************************
133      * Is block less then 64k in length?
134      */
135     if (g_first->sequence != 1 || g_first->length == 1)
136     {
137         return GlobalUnlock(block);
138     }
139
140     /******************************************************************
141      * Make sure we have a lock on this block.
142      */
143 #ifdef HAVE_IPC
144     if (g_first->linear_count > 1)
145     {
146         g_first->linear_count--;
147     }
148     else if (g_first->linear_count == 1)
149     {
150         g = g_first;
151         loc_idx = (((unsigned int) g_first - (unsigned int) SHM_RANGE_START) 
152                    / 0x10000);
153         for (i = 0; i < g_first->length; i++, g = g->next)
154         {
155             shmdt(g->linear_addr);
156             g->linear_addr = NULL;
157             MemoryKeys[i] = -1;
158         }
159         
160         g_first->linear_count = 0;
161         return 0;
162     }
163 #endif /* HAVE_IPC */
164
165     return 0;
166 }
167 /**********************************************************************/
168 \f
169 void LinearTest()
170 {
171 #if 0
172     unsigned int handle;
173     int *seg_ptr;
174     int *lin_ptr;
175     int seg, i;
176     int *p;
177
178     handle = GlobalAlloc(0, 0x40000);
179     seg_ptr = GlobalLock(handle);
180     lin_ptr = GlobalLinearLock(handle);
181
182     for (seg = 0; seg < 4; seg++)
183     {
184         p = (int *) ((char *) seg_ptr + (0x80000 * seg));
185         for (i = 0; i < (0x10000 / sizeof(int)); i++, p++)
186             *p = (seg * (0x10000 / sizeof(int))) + i;
187     }
188     
189     p = lin_ptr;
190     for (i = 0; i < (0x40000 / sizeof(int)); i++, p++)
191     {
192         if (*p != i)
193             printf("lin_ptr[%x] = %x\n", i, *p);
194     }
195 #endif
196 }