source: trunk/dll/strutil.c@ 1460

Last change on this file since 1460 was 1460, checked in by Gregg Young, 16 years ago

Make GetPString more SMP safe

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1
2/***********************************************************************
3
4 $Id: strutil.c 1460 2009-09-19 21:11:12Z gyoung $
5
6 External strings support - stored in STRINGTABLE
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2006, 2009 Steven H. Levine
10
11 22 Jul 06 SHL Comments
12 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
13 05 Jan 08 SHL Rename from string.c to avoid string.h conflict
14 03 Feb 09 SHL Switch to STRINGTABLE and const return
15 19 Sep 09 GKY Make GetPString more SMP safe
16
17***********************************************************************/
18
19#include <stdio.h>
20#include <share.h>
21#include <string.h>
22
23#define INCL_DOSPROCESS // DosSleep
24
25#include "fm3dll.h"
26#include "fm3str.h"
27#include "init.h" // Data declaration(s)
28#include "mainwnd.h" // FM3ModHandle
29#include "wrappers.h"
30#include "errutil.h"
31#include "strutil.h"
32#include "version.h"
33
34static PSZ pszSrcFile = __FILE__;
35
36//== GetPString() return a readonly pointer to the requested string in memory ==
37
38PCSZ GetPString(ULONG id)
39{
40 PSZ psz;
41 LONG l;
42 CHAR sz[257];
43 ULONG ulNewFirstId;
44 ULONG ulNewLastId;
45
46 static PSZ *pLoadedStrings;
47 static ULONG ulFirstId;
48 static ULONG ulLastId;
49
50 // Strings that must be combined because stringtable items limited to 256
51 static struct LongString {
52 ULONG id;
53 ULONG sub_id;
54 } LongStrings[] = {
55 {IDS_SUGGEST1TEXT, IDS_SUGGEST1TEXT1},
56 {IDS_SUGGEST1TEXT, IDS_SUGGEST1TEXT2},
57 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT1},
58 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT2},
59 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT3},
60 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT4},
61 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT5},
62 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT6},
63 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT7},
64 {IDS_INIBINARYDATASKIPTEXT, IDS_INIBINARYDATASKIPTEXT1},
65 {IDS_INIBINARYDATASKIPTEXT, IDS_INIBINARYDATASKIPTEXT2},
66 {IDS_INSTANTHELPTEXT, IDS_INSTANTHELPTEXT1},
67 {IDS_INSTANTHELPTEXT, IDS_INSTANTHELPTEXT2},
68 {IDS_FSDERRORTEXT, IDS_FSDERRORTEXT1},
69 {IDS_FSDERRORTEXT, IDS_FSDERRORTEXT2},
70 {IDS_LANERRORTEXT, IDS_LANERRORTEXT1},
71 {IDS_LANERRORTEXT, IDS_LANERRORTEXT2},
72 {IDS_MAKESHADOWHELPTEXT, IDS_MAKESHADOWHELPTEXT1},
73 {IDS_MAKESHADOWHELPTEXT, IDS_MAKESHADOWHELPTEXT2},
74 {IDS_UNDELETEHELPTEXT, IDS_UNDELETEHELPTEXT1},
75 {IDS_UNDELETEHELPTEXT, IDS_UNDELETEHELPTEXT2},
76 {IDS_KILLPROCHELPTEXT, IDS_KILLPROCHELPTEXT1},
77 {IDS_KILLPROCHELPTEXT, IDS_KILLPROCHELPTEXT2},
78 {IDS_ARCNOTTHERETEXT, IDS_ARCNOTTHERETEXT1},
79 {IDS_ARCNOTTHERETEXT, IDS_ARCNOTTHERETEXT2},
80 {IDS_FM2CMDHELPTEXT, IDS_FM2CMDHELPTEXT1},
81 {IDS_FM2CMDHELPTEXT, IDS_FM2CMDHELPTEXT2},
82 {IDS_FM2CMDHELPTEXT, IDS_FM2CMDHELPTEXT3}
83 };
84
85 static UINT cLongStrings = sizeof(LongStrings) / sizeof(struct LongString);
86
87 static volatile INT cBusy; // Need to be MT-safe
88 static ULONG ulDbgId; // 13 Jan 09 SHL fixme to be gone?
89 static UINT uDbgState; // 03 Feb 09 SHL fixme to be gone?
90 static ULONG ulDbgTid; // 13 Jan 09 SHL fixme to be gone?
91
92 UINT c;
93 // 23 Jan 09 SHL fixme to use SMP safe inc/dec?
94 extern void SMPSafeInc(void);
95 extern void SMPSafeDec(void);
96 #pragma aux SMPSafeInc = "lock inc cBusy" modify exact [];
97 #pragma aux SMPSafeDec = "lock dec cBusy" modify exact [];
98 // SMPSafeInc();
99 for (c = 0; ; c++) {
100 if (SMPSafeInc(), cBusy == 1)
101 break;
102 SMPSafeDec();
103 // Hold off 1 cycle before reporting since some contention expected
104 if (c == 1)
105 DbgMsg(pszSrcFile, __LINE__, "GetPString(%lu) waiting for tid %lu GetPString(%lu), state=%u", id, ulDbgTid, ulDbgId, uDbgState);
106 DosSleep(1); // Let current owner finish
107 }
108 if (c > 1)
109 DbgMsg(pszSrcFile, __LINE__, "continuing with GetPString(%lu) after tid %lu GetPString(%lu), state=%u", id, ulDbgTid, ulDbgId, uDbgState);
110
111 // Remember id and thread ordinal for diagnosing MT hangs
112 // Use fast DosGetInfoBlocks to ensure debug logic does not change timing
113 {
114 extern PTIB2 GetPTIB2(void);
115 #pragma aux GetPTIB2 = "mov eax,fs:[12]" value [eax];
116 // PIB *ppib;
117 // TIB *ptib;
118 TIB2 *ptib2 = GetPTIB2();
119 // APIRET apiret = DosGetInfoBlocks(&ptib, &ppib);
120 ulDbgId = id;
121 // ulDbgTid = apiret == 0 ? ptib->tib_ptib2->tib2_ultid : 0;
122 ulDbgTid = ptib2->tib2_ultid;
123 }
124
125 // DbgMsg(pszSrcFile, __LINE__, "Fetching %lu", id);
126
127 // If string already loaded, return it now
128 if (id >= ulFirstId &&
129 id <= ulLastId &&
130 pLoadedStrings &&
131 (psz = pLoadedStrings[id - ulFirstId]) != NULL) {
132 cBusy--;
133 if (((ULONG)psz & 0xffff0000) == 0)
134 DbgMsg(pszSrcFile, __LINE__, "id %lu corrupted %p", id, psz);
135 // DbgMsg(pszSrcFile, __LINE__, "id %lu \"%s\"", id, psz ? psz : "(null)");
136 return psz;
137 }
138
139 // Try to load
140 // 11 Jan 09 SHL fixme to use global HAB?
141 uDbgState = 1;
142 l = WinLoadString((HAB)NULL, FM3ModHandle, id, sizeof(sz), sz);
143 uDbgState = 2;
144
145 if (l != 0) {
146 psz = xstrdup(sz, pszSrcFile, __LINE__);
147 if (!psz) {
148 cBusy--;
149 return NullStr;
150 }
151 }
152 else {
153 // Assume string must be built from multiple strings - find first
154 UINT i;
155 psz = NULL;
156 for (i = 0; i < cLongStrings && LongStrings[i].id != id; i++); // Scan
157
158 if (i < cLongStrings) {
159 // Combine stringtable items to build long string
160 // DbgMsg(pszSrcFile, __LINE__, "Building long string %lu", id);
161 for (; LongStrings[i].id == id; i++) {
162 uDbgState = 3;
163 l = WinLoadString((HAB)NULL, FM3ModHandle, LongStrings[i].sub_id, sizeof(sz), sz);
164 uDbgState = 4;
165 if (l == 0) {
166 cBusy--;
167 Runtime_Error(pszSrcFile, __LINE__, "string %lu missing", LongStrings[i].sub_id);
168 xfree(psz, pszSrcFile, __LINE__);
169 return NullStr;
170 }
171 if (!psz) {
172 // Remember 1st string
173 psz = strdup(sz);
174 if (!psz) {
175 cBusy--;
176 return NullStr;
177 }
178 }
179 else {
180 // Append string
181 UINT curLen = strlen(psz);
182 PSZ psz2 = xrealloc(psz, curLen + l + 1, pszSrcFile, __LINE__);
183 if (!psz2) {
184 xfree(psz, pszSrcFile, __LINE__);
185 cBusy--;
186 return NullStr;
187 }
188 memcpy(psz2 + curLen, sz, l); // Append
189 *(psz2 + curLen + l) = 0; // Terminate
190 psz = psz2; // Remember
191 l += curLen;
192 }
193 } // while
194 } // if long
195 } // if loaded
196
197 if (l == 0) {
198 DbgMsg(pszSrcFile, __LINE__, "Error loading %lu", id);
199 sprintf(sz, "** Error loading id %lu **", id);
200 psz = xstrdup(sz, pszSrcFile, __LINE__);
201 if (psz)
202 l = strlen(sz);
203 else
204 psz = NullStr; // Oh heck
205 }
206
207 uDbgState = 5;
208 // Add to cache
209 // DbgMsg(pszSrcFile, __LINE__, "Caching %lu", id);
210
211 // Calculate new array limits
212 if (!pLoadedStrings) {
213 ulNewFirstId = id;
214 ulNewLastId = id;
215 ulFirstId = id;
216 ulLastId = id;
217 }
218 else {
219 ulNewFirstId = id < ulFirstId ? id : ulFirstId;
220 ulNewLastId = id > ulLastId ? id : ulLastId;
221 }
222
223 if (ulNewFirstId != ulFirstId ||
224 ulNewLastId != ulLastId ||
225 !pLoadedStrings) {
226 PSZ *pNewLoadedStrings;
227 // DbgMsg(pszSrcFile, __LINE__, "Reallocating for %lu", id);
228 pNewLoadedStrings = xrealloc(pLoadedStrings,
229 (ulNewLastId - ulNewFirstId + 1) * sizeof(PSZ),
230 pszSrcFile, __LINE__);
231 if (!pNewLoadedStrings) {
232 cBusy--;
233 Runtime_Error(pszSrcFile, __LINE__, "realloc failed");
234 xfree(psz, pszSrcFile, __LINE__);
235 return NullStr;
236 }
237 // Align existing entries and zero fill unused entries as needed
238 if (ulNewFirstId < ulFirstId) {
239 // Move room for new entries at head of array
240 memmove(pNewLoadedStrings + (ulFirstId - ulNewFirstId),
241 pNewLoadedStrings,
242 (ulLastId - ulFirstId + 1) * sizeof(PSZ));
243 // Null unused placeholder entries
244 if (ulFirstId - ulNewFirstId > 1)
245 memset(pNewLoadedStrings + 1, 0, (ulFirstId - ulNewFirstId - 1) * sizeof(PSZ));
246 }
247 if (ulNewLastId - ulLastId > 1) {
248 // Null unused placeholder entries
249 memset(pNewLoadedStrings + (ulLastId - ulNewFirstId + 1),
250 0,
251 (ulNewLastId - ulLastId - 1) * sizeof(PSZ));
252 }
253 pLoadedStrings = pNewLoadedStrings;
254 ulFirstId = ulNewFirstId;
255 ulLastId = ulNewLastId;
256 }
257
258 uDbgState = 6;
259 pLoadedStrings[id - ulFirstId] = psz;
260 cBusy--;
261 // DbgMsg(pszSrcFile, __LINE__, "id %lu \"%s\"", id, psz ? psz : "(null)");
262 return psz;
263}
264
265#pragma alloc_text(STRINGS,LoadStrings,GetPString)
Note: See TracBrowser for help on using the repository browser.