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
RevLine 
[333]1
2/***********************************************************************
3
4 $Id: strutil.c 1460 2009-09-19 21:11:12Z gyoung $
5
[1394]6 External strings support - stored in STRINGTABLE
[333]7
8 Copyright (c) 1993-98 M. Kimes
[1394]9 Copyright (c) 2006, 2009 Steven H. Levine
[333]10
11 22 Jul 06 SHL Comments
[793]12 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
[907]13 05 Jan 08 SHL Rename from string.c to avoid string.h conflict
[1394]14 03 Feb 09 SHL Switch to STRINGTABLE and const return
[1460]15 19 Sep 09 GKY Make GetPString more SMP safe
[333]16
17***********************************************************************/
18
[2]19#include <stdio.h>
20#include <share.h>
[1394]21#include <string.h>
[333]22
[1394]23#define INCL_DOSPROCESS // DosSleep
24
[1213]25#include "fm3dll.h"
26#include "fm3str.h"
27#include "init.h" // Data declaration(s)
[1394]28#include "mainwnd.h" // FM3ModHandle
29#include "wrappers.h"
30#include "errutil.h"
[907]31#include "strutil.h"
[2]32#include "version.h"
33
[1394]34static PSZ pszSrcFile = __FILE__;
[907]35
[1394]36//== GetPString() return a readonly pointer to the requested string in memory ==
[2]37
[1394]38PCSZ GetPString(ULONG id)
[333]39{
[1394]40 PSZ psz;
41 LONG l;
42 CHAR sz[257];
43 ULONG ulNewFirstId;
44 ULONG ulNewLastId;
[2]45
[1394]46 static PSZ *pLoadedStrings;
47 static ULONG ulFirstId;
48 static ULONG ulLastId;
[333]49
[1394]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 };
[2]84
[1394]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++) {
[1460]100 if (SMPSafeInc(), cBusy == 1)
[1394]101 break;
[1460]102 SMPSafeDec();
[1394]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;
[2]150 }
151 }
[1394]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
[2]157
[1394]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
[2]205 }
206
[1394]207 uDbgState = 5;
208 // Add to cache
209 // DbgMsg(pszSrcFile, __LINE__, "Caching %lu", id);
[2]210
[1394]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 }
[2]222
[1394]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 }
[2]257
[1394]258 uDbgState = 6;
259 pLoadedStrings[id - ulFirstId] = psz;
260 cBusy--;
261 // DbgMsg(pszSrcFile, __LINE__, "id %lu \"%s\"", id, psz ? psz : "(null)");
262 return psz;
[2]263}
[793]264
265#pragma alloc_text(STRINGS,LoadStrings,GetPString)
Note: See TracBrowser for help on using the repository browser.