View | Details | Raw Unified | Return to bug 8566
Collapse All | Expand All

(-)a/mcs/class/corlib/Test/System.Threading/WaitHandleTest.cs (+81 lines)
Lines 315-320 namespace MonoTests.System.Threading { Link Here
315
			WaitHandle.WaitAny (new WaitHandle [0]);
315
			WaitHandle.WaitAny (new WaitHandle [0]);
316
		}
316
		}
317
317
318
		[Test]
319
		public void InterrupedWaitAny ()
320
		{
321
			using (var m1 = new Mutex (true)) {
322
				using (var m2 = new Mutex (true)) {
323
					using (var done = new ManualResetEvent (false)) {
324
						var thread = new Thread (() =>
325
						{
326
							try {
327
								WaitHandle.WaitAny (new WaitHandle [] { m1, m2 });
328
							} catch (ThreadInterruptedException) {
329
								done.Set ();
330
							}
331
						});
332
						thread.Start ();
333
						Thread.Sleep (100); // wait a bit so the thread can enter its wait
334
						thread.Interrupt ();
335
336
						Assert.IsTrue (thread.Join (1000), "Join");
337
						Assert.IsTrue (done.WaitOne (1000), "done");
338
339
						m1.ReleaseMutex ();
340
						m2.ReleaseMutex ();
341
					}
342
				}
343
			}
344
		}
345
		
346
		[Test]
347
		public void InterrupedWaitAll ()
348
		{
349
			using (var m1 = new Mutex (true)) {
350
				using (var m2 = new Mutex (true)) {
351
					using (var done = new ManualResetEvent (false)) {
352
						var thread = new Thread (() =>
353
						                         {
354
							try {
355
								WaitHandle.WaitAll (new WaitHandle [] { m1, m2 });
356
							} catch (ThreadInterruptedException) {
357
								done.Set ();
358
							}
359
						});
360
						thread.Start ();
361
						Thread.Sleep (100); // wait a bit so the thread can enter its wait
362
						thread.Interrupt ();
363
364
						Assert.IsTrue (thread.Join (1000), "Join");
365
						Assert.IsTrue (done.WaitOne (1000), "done");
366
367
						m1.ReleaseMutex ();
368
						m2.ReleaseMutex ();
369
					}
370
				}
371
			}
372
		}
373
		
374
		[Test]
375
		public void InterrupedWaitOne ()
376
		{
377
			using (var m1 = new Mutex (true)) {
378
				using (var done = new ManualResetEvent (false)) {
379
					var thread = new Thread (() =>
380
					                         {
381
						try {
382
							m1.WaitOne ();
383
						} catch (ThreadInterruptedException) {
384
							done.Set ();
385
						}
386
					});
387
					thread.Start ();
388
					Thread.Sleep (100); // wait a bit so the thread can enter its wait
389
					thread.Interrupt ();
390
391
					Assert.IsTrue (thread.Join (1000), "Join");
392
					Assert.IsTrue (done.WaitOne (1000), "done");
393
394
					m1.ReleaseMutex ();
395
				}
396
			}
397
		}
398
318
	}
399
	}
319
}
400
}
320
401
(-)a/mono/metadata/threads.c (-29 / +38 lines)
Lines 1362-1367 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *thi Link Here
1362
	return(FALSE);
1362
	return(FALSE);
1363
}
1363
}
1364
1364
1365
static gint32
1366
mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1367
{
1368
	MonoException *exc;
1369
	guint32 ret;
1370
	guint32 start;
1371
	guint32 diff;
1372
1373
	start = (ms == -1) ? 0 : mono_msec_ticks ();
1374
	do {
1375
		if (multiple)
1376
			ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, ms, alertable);
1377
		else
1378
			ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1379
1380
		if (ret != WAIT_IO_COMPLETION)
1381
			break;
1382
1383
		exc = mono_thread_execute_interruption (thread);
1384
		if (exc)
1385
			mono_raise_exception (exc);
1386
1387
		if (ms == -1)
1388
			continue;
1389
1390
		/* Re-calculate ms according to the time passed */
1391
		diff = mono_msec_ticks () - start;
1392
		ms -= diff;
1393
	} while (ms > 0);
1394
	
1395
	return ret;
1396
}
1397
1365
/* FIXME: exitContext isnt documented */
1398
/* FIXME: exitContext isnt documented */
1366
gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1399
gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1367
{
1400
{
Lines 1389-1395 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ Link Here
1389
1422
1390
	mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1423
	mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1391
	
1424
	
1392
	ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE);
1425
	ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1393
1426
1394
	mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1427
	mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1395
1428
Lines 1398-1409 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ Link Here
1398
	if(ret==WAIT_FAILED) {
1431
	if(ret==WAIT_FAILED) {
1399
		THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1432
		THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1400
		return(FALSE);
1433
		return(FALSE);
1401
	} else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
1434
	} else if(ret==WAIT_TIMEOUT) {
1402
		/* Do we want to try again if we get
1403
		 * WAIT_IO_COMPLETION? The documentation for
1404
		 * WaitHandle doesn't give any clues.  (We'd have to
1405
		 * fiddle with the timeout if we retry.)
1406
		 */
1407
		THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1435
		THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1408
		return(FALSE);
1436
		return(FALSE);
1409
	}
1437
	}
Lines 1420-1426 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha Link Here
1420
	guint32 i;
1448
	guint32 i;
1421
	MonoObject *waitHandle;
1449
	MonoObject *waitHandle;
1422
	MonoInternalThread *thread = mono_thread_internal_current ();
1450
	MonoInternalThread *thread = mono_thread_internal_current ();
1423
	guint32 start;
1424
1451
1425
	/* Do this WaitSleepJoin check before creating objects */
1452
	/* Do this WaitSleepJoin check before creating objects */
1426
	mono_thread_current_check_pending_interrupt ();
1453
	mono_thread_current_check_pending_interrupt ();
Lines 1440-1459 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha Link Here
1440
1467
1441
	mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1468
	mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1442
1469
1443
	start = (ms == -1) ? 0 : mono_msec_ticks ();
1470
	ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1444
	do {
1445
		ret = WaitForMultipleObjectsEx (numhandles, handles, FALSE, ms, TRUE);
1446
		if (ret != WAIT_IO_COMPLETION)
1447
			break;
1448
		if (ms != -1) {
1449
			guint32 diff;
1450
1451
			diff = mono_msec_ticks () - start;
1452
			ms -= diff;
1453
			if (ms <= 0)
1454
				break;
1455
		}
1456
	} while (ms == -1 || ms > 0);
1457
1471
1458
	mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1472
	mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1459
1473
Lines 1489-1507 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this Link Here
1489
1503
1490
	mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1504
	mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1491
	
1505
	
1492
	ret=WaitForSingleObjectEx (handle, ms, TRUE);
1506
	ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1493
	
1507
	
1494
	mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1508
	mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1495
	
1509
	
1496
	if(ret==WAIT_FAILED) {
1510
	if(ret==WAIT_FAILED) {
1497
		THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1511
		THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1498
		return(FALSE);
1512
		return(FALSE);
1499
	} else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
1513
	} else if(ret==WAIT_TIMEOUT) {
1500
		/* Do we want to try again if we get
1501
		 * WAIT_IO_COMPLETION? The documentation for
1502
		 * WaitHandle doesn't give any clues.  (We'd have to
1503
		 * fiddle with the timeout if we retry.)
1504
		 */
1505
		THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1514
		THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1506
		return(FALSE);
1515
		return(FALSE);
1507
	}
1516
	}

Return to bug 8566