3
3
using System . Diagnostics ;
4
4
using System . Linq ;
5
5
using System . Text ;
6
+ using System . Threading ;
6
7
using System . Windows . Forms ;
7
8
using System . Xml ;
8
9
using System . Xml . Linq ;
@@ -17,18 +18,41 @@ namespace GPUPrefSwitcher
17
18
/// </summary>
18
19
public class PreferencesXML
19
20
{
21
+ public class ThreadSafeXmlDoc : XmlDocument
22
+ {
23
+ //private XmlDocument xmlDocument = new XmlDocument();
24
+ private SemaphoreSlim SemaphoreSlim = new SemaphoreSlim ( 1 ) ;
20
25
21
- public static readonly string XML_PREFERENCES_PATH = Program . SavedDataPath + "Preferences.xml" ;
26
+ public override void Load ( string path )
27
+ {
28
+ SemaphoreSlim . Wait ( ) ;
29
+ try
30
+ {
31
+ base . Load ( path ) ;
32
+ }
33
+ finally { SemaphoreSlim . Release ( ) ; }
34
+ }
35
+
36
+ public override void Save ( string path )
37
+ {
38
+ SemaphoreSlim . Wait ( ) ;
39
+ try
40
+ {
41
+ base . Save ( path ) ;
42
+ }
43
+ finally { SemaphoreSlim . Release ( ) ; }
44
+ }
45
+ }
22
46
23
- XmlDocument xmlDocument = new XmlDocument ( ) ;
47
+ public static readonly string XML_PREFERENCES_PATH = Program . SavedDataPath + "Preferences.xml" ;
48
+ private ThreadSafeXmlDoc threadSafeXmlDoc = new ThreadSafeXmlDoc ( ) ;
24
49
25
- private object WriteLock = new ( ) ;
26
50
public PreferencesXML ( )
27
51
{
28
52
29
53
try
30
54
{
31
- xmlDocument . Load ( XML_PREFERENCES_PATH ) ;
55
+ threadSafeXmlDoc . Load ( XML_PREFERENCES_PATH ) ;
32
56
}
33
57
catch ( XmlException )
34
58
{
@@ -68,7 +92,7 @@ internal void ReloadXML()
68
92
{
69
93
try
70
94
{
71
- xmlDocument . Load ( XML_PREFERENCES_PATH ) ;
95
+ threadSafeXmlDoc . Load ( XML_PREFERENCES_PATH ) ;
72
96
}
73
97
catch ( Exception )
74
98
{
@@ -122,7 +146,7 @@ public List<AppEntry> GetAppEntries()
122
146
123
147
//ReloadXML(); //performance hog?
124
148
125
- XmlNodeList xmlAppEntries = xmlDocument . GetElementsByTagName ( XML_APP_ENTRY ) ;
149
+ XmlNodeList xmlAppEntries = threadSafeXmlDoc . GetElementsByTagName ( XML_APP_ENTRY ) ;
126
150
127
151
List < AppEntry > appEntries = new List < AppEntry > ( ) ;
128
152
@@ -189,7 +213,7 @@ public IEnumerable<string> GetAppPaths()
189
213
{
190
214
191
215
ReloadXML ( ) ;
192
- XmlNodeList pathEntries = xmlDocument . GetElementsByTagName ( XML_APP_PATH ) ;
216
+ XmlNodeList pathEntries = threadSafeXmlDoc . GetElementsByTagName ( XML_APP_PATH ) ;
193
217
194
218
foreach ( XmlNode pathEntryNode in pathEntries )
195
219
{
@@ -219,7 +243,7 @@ XmlNodeList GetAppEntryFileSwapperXmlNodes(XmlNode appEntry)
219
243
220
244
XmlNode AppEntryNodeByAppPath ( string path )
221
245
{
222
- XmlNodeList xmlAppEntries = xmlDocument . GetElementsByTagName ( XML_APP_ENTRY ) ;
246
+ XmlNodeList xmlAppEntries = threadSafeXmlDoc . GetElementsByTagName ( XML_APP_ENTRY ) ;
223
247
224
248
foreach ( XmlNode xmlAppEntry in xmlAppEntries )
225
249
{
@@ -250,33 +274,33 @@ internal void AddAppEntryAndSave(AppEntry appEntry)
250
274
throw new InvalidOperationException ( $ "Tried to add an AppEntry with an AppPath that already exists in the data store: { appEntry . AppPath } — this is undefined behavior.") ;
251
275
}
252
276
253
- XmlNode root = xmlDocument . DocumentElement ;
277
+ XmlNode root = threadSafeXmlDoc . DocumentElement ;
254
278
{
255
- XmlElement xmlAppEntry = xmlDocument . CreateElement ( XML_APP_ENTRY ) ;
256
- XmlElement xmlPath = xmlDocument . CreateElement ( XML_APP_PATH ) ;
279
+ XmlElement xmlAppEntry = threadSafeXmlDoc . CreateElement ( XML_APP_ENTRY ) ;
280
+ XmlElement xmlPath = threadSafeXmlDoc . CreateElement ( XML_APP_PATH ) ;
257
281
{
258
282
xmlPath . InnerText = appEntry . AppPath ;
259
283
{
260
- XmlElement xmlGpuPref = xmlDocument . CreateElement ( XML_GPU_PREFERENCE ) ;
284
+ XmlElement xmlGpuPref = threadSafeXmlDoc . CreateElement ( XML_GPU_PREFERENCE ) ;
261
285
{
262
286
xmlGpuPref . SetAttribute ( XML_ATTR_ENABLESWITCHER , appEntry . EnableSwitcher . ToString ( ) ) ;
263
287
xmlGpuPref . SetAttribute ( XML_ATTR_ENABLEFILESWAPPER , appEntry . EnableFileSwapper . ToString ( ) ) ;
264
288
265
- XmlElement runOnBattery = xmlDocument . CreateElement ( XML_RUN_ON_BATTERY_PATH ) ;
266
- XmlElement runPluggedIn = xmlDocument . CreateElement ( XML_RUN_PLUGGED_IN_PATH ) ;
289
+ XmlElement runOnBattery = threadSafeXmlDoc . CreateElement ( XML_RUN_ON_BATTERY_PATH ) ;
290
+ XmlElement runPluggedIn = threadSafeXmlDoc . CreateElement ( XML_RUN_PLUGGED_IN_PATH ) ;
267
291
xmlGpuPref . AppendChild ( runOnBattery ) ;
268
292
xmlGpuPref . AppendChild ( runPluggedIn ) ;
269
293
}
270
- XmlElement xmlPluggedIn = xmlDocument . CreateElement ( XML_PLUGGED_IN ) ;
294
+ XmlElement xmlPluggedIn = threadSafeXmlDoc . CreateElement ( XML_PLUGGED_IN ) ;
271
295
{
272
296
xmlPluggedIn . InnerText = appEntry . GPUPrefPluggedIn . ToString ( ) ;
273
297
}
274
298
//xmlPluggedIn.InnerText = defaultPluggedin;
275
- XmlElement xmlOnBattery = xmlDocument . CreateElement ( XML_ON_BATTERY ) ;
299
+ XmlElement xmlOnBattery = threadSafeXmlDoc . CreateElement ( XML_ON_BATTERY ) ;
276
300
{
277
301
xmlOnBattery . InnerText = appEntry . GPUPrefOnBattery . ToString ( ) ;
278
302
}
279
- XmlElement xmlFileSwapper = xmlDocument . CreateElement ( XML_FILE_SWAPPER ) ;
303
+ XmlElement xmlFileSwapper = threadSafeXmlDoc . CreateElement ( XML_FILE_SWAPPER ) ;
280
304
281
305
282
306
//xmlOnBattery.InnerText = defaultOnBattery;
@@ -291,17 +315,17 @@ internal void AddAppEntryAndSave(AppEntry appEntry)
291
315
292
316
if ( appEntry . PendingAddToRegistry )
293
317
{
294
- XmlElement pendingAdd = xmlDocument . CreateElement ( XML_PENDING_ADD ) ;
318
+ XmlElement pendingAdd = threadSafeXmlDoc . CreateElement ( XML_PENDING_ADD ) ;
295
319
xmlAppEntry . AppendChild ( pendingAdd ) ;
296
320
}
297
321
298
- XmlElement seenInRegistry = xmlDocument . CreateElement ( XML_SEEN_IN_REGISTRY ) ;
322
+ XmlElement seenInRegistry = threadSafeXmlDoc . CreateElement ( XML_SEEN_IN_REGISTRY ) ;
299
323
seenInRegistry . InnerText = appEntry . SeenInRegistry . ToString ( ) ;
300
324
xmlAppEntry . AppendChild ( seenInRegistry ) ;
301
325
}
302
326
}
303
327
304
- xmlDocument . Save ( XML_PREFERENCES_PATH ) ;
328
+ threadSafeXmlDoc . Save ( XML_PREFERENCES_PATH ) ;
305
329
}
306
330
}
307
331
@@ -313,19 +337,16 @@ internal void AddAppEntryAndSave(AppEntry appEntry)
313
337
/// <exception cref="XMLHelperException"></exception>
314
338
internal bool TryDeleteAppEntryAndSave ( string path )
315
339
{
316
- lock ( WriteLock )
317
- {
318
- ReloadXML ( ) ;
340
+ ReloadXML ( ) ;
319
341
320
- XmlNode xmlAppEntry = AppEntryNodeByAppPath ( path ) ;
321
- if ( xmlAppEntry == null ) { return false ; }
342
+ XmlNode xmlAppEntry = AppEntryNodeByAppPath ( path ) ;
343
+ if ( xmlAppEntry == null ) { return false ; }
322
344
323
- xmlDocument . DocumentElement . RemoveChild ( xmlAppEntry ) ;
345
+ threadSafeXmlDoc . DocumentElement . RemoveChild ( xmlAppEntry ) ;
324
346
325
- xmlDocument . Save ( XML_PREFERENCES_PATH ) ;
347
+ threadSafeXmlDoc . Save ( XML_PREFERENCES_PATH ) ;
326
348
327
- return true ;
328
- }
349
+ return true ;
329
350
}
330
351
331
352
public void ModifyAppEntryAndSave ( string path , AppEntry newAppEntry ) //TODO file swapper functionality
@@ -388,7 +409,7 @@ public void ModifyAppEntryAndSave(string path, AppEntry newAppEntry) //TODO file
388
409
//TODO this is jank, I think Switcher.cs needs to not have access to this and only access to AppEntrySaveHandler instead
389
410
if ( newAppEntry . PendingAddToRegistry )
390
411
{
391
- XmlElement pendingAddToRegistry = xmlDocument . CreateElement ( XML_PENDING_ADD ) ;
412
+ XmlElement pendingAddToRegistry = threadSafeXmlDoc . CreateElement ( XML_PENDING_ADD ) ;
392
413
if ( xmlAppEntry . SelectSingleNode ( XML_PENDING_ADD ) == null )
393
414
{
394
415
xmlAppEntry . AppendChild ( pendingAddToRegistry ) ;
@@ -419,7 +440,7 @@ public void ModifyAppEntryAndSave(string path, AppEntry newAppEntry) //TODO file
419
440
{
420
441
string newFileSwapperPath = newFileSwapperPaths [ i ] ;
421
442
422
- XmlElement xmlElement = xmlDocument . CreateElement ( XML_SWAP_PATH ) ;
443
+ XmlElement xmlElement = threadSafeXmlDoc . CreateElement ( XML_SWAP_PATH ) ;
423
444
424
445
xmlElement . SetAttribute ( XML_ATTR_SWAPPATHSTATUS , PowerLineStatusConversions . PowerLineStatusToOfflineOrOnline ( newAppEntry . SwapperStates [ i ] ) ) ; //TODO: does this gauruntee order?
425
446
@@ -429,7 +450,7 @@ public void ModifyAppEntryAndSave(string path, AppEntry newAppEntry) //TODO file
429
450
}
430
451
}
431
452
432
- xmlDocument . Save ( XML_PREFERENCES_PATH ) ;
453
+ threadSafeXmlDoc . Save ( XML_PREFERENCES_PATH ) ;
433
454
} /* catch (NullReferenceException)
434
455
{
435
456
throw new XmlException($"An error occured while trying to modify AppEntry with AppPath {path}; check if the entry is malformed in Preferences.xml");
@@ -449,7 +470,7 @@ internal void WriteToRegistry(PowerLineStatus powerLineStatus)
449
470
450
471
//List<string> regPathValues = RegistryHelper.GetGpuPrefPathvalueNames().ToList();
451
472
452
- XmlNodeList xmlAppEntries = xmlDocument . GetElementsByTagName ( XML_APP_ENTRY ) ;
473
+ XmlNodeList xmlAppEntries = threadSafeXmlDoc . GetElementsByTagName ( XML_APP_ENTRY ) ;
453
474
454
475
foreach ( XmlNode xmlAppEntry in xmlAppEntries )
455
476
{
@@ -643,7 +664,7 @@ private string IdentifyCriticalAppEntryErrors(XmlElement appEntryNode, int lineP
643
664
644
665
if ( sb . ToString ( ) != NO_ERRORS_STRING )
645
666
{
646
- string xmlDocumentToString = xmlDocument . OuterXml ;
667
+ string xmlDocumentToString = threadSafeXmlDoc . OuterXml ;
647
668
sb . Insert ( 0 , $ "The AppEntry node starting on line { linePosition } has the following errors:\n ") ;
648
669
}
649
670
@@ -660,7 +681,7 @@ public string GetAllCriticalXmlAppEntryErrors()
660
681
{
661
682
StringBuilder sb = new ( NO_ERRORS_STRING ) ;
662
683
//apparently you can call SelectNodes() from xmlDocument which returns nothing, so you have to reference DocumentElement first...
663
- var appEntryNodes = xmlDocument . DocumentElement . SelectNodes ( XML_APP_ENTRY ) ;
684
+ var appEntryNodes = threadSafeXmlDoc . DocumentElement . SelectNodes ( XML_APP_ENTRY ) ;
664
685
for ( int i = 0 ; i < appEntryNodes . Count ; i ++ )
665
686
{
666
687
XmlNode node = appEntryNodes [ i ] ;
@@ -709,7 +730,7 @@ void CheckForDuplicatePaths()
709
730
710
731
internal void DebugPrintXML ( )
711
732
{
712
- XmlNodeList nodeList = xmlDocument . GetElementsByTagName ( XML_APP_ENTRY ) ;
733
+ XmlNodeList nodeList = threadSafeXmlDoc . GetElementsByTagName ( XML_APP_ENTRY ) ;
713
734
714
735
foreach ( XmlElement e in nodeList )
715
736
{
0 commit comments