@@ -93,6 +93,9 @@ extern "C"
93
93
} \
94
94
} while (false )
95
95
96
+ // On macOS 26, sem_open fails if debugger and debugee are signed with different team ids.
97
+ // Use fifos instead of semaphores to avoid this issue, https://github.com/dotnet/runtime/issues/116545
98
+ #define ENABLE_RUNTIME_EVENTS_OVER_PIPES
96
99
#endif // __APPLE__
97
100
98
101
#ifdef __NetBSD__
@@ -1401,21 +1404,217 @@ static uint64_t HashSemaphoreName(uint64_t a, uint64_t b)
1401
1404
static const char *const TwoWayNamedPipePrefix = " clr-debug-pipe" ;
1402
1405
static const char * IpcNameFormat = " %s-%d-%llu-%s" ;
1403
1406
1404
- /* ++
1405
- PAL_NotifyRuntimeStarted
1407
+ #ifdef ENABLE_RUNTIME_EVENTS_OVER_PIPES
1408
+ static const char * RuntimeStartupPipeName = " st" ;
1409
+ static const char * RuntimeContinuePipeName = " co" ;
1406
1410
1407
- Signals the debugger waiting for runtime startup notification to continue and
1408
- waits until the debugger signals us to continue.
1411
+ #define PIPE_OPEN_RETRY_DELAY_NS 500000000 // 500 ms
1409
1412
1410
- Parameters:
1411
- None
1413
+ typedef enum
1414
+ {
1415
+ RuntimeEventsOverPipes_Disabled = 0 ,
1416
+ RuntimeEventsOverPipes_Succeeded = 1 ,
1417
+ RuntimeEventsOverPipes_Failed = 2 ,
1418
+ } RuntimeEventsOverPipes;
1412
1419
1413
- Return value:
1414
- TRUE - successfully launched by debugger, FALSE - not launched or some failure in the handshake
1415
- --*/
1420
+ typedef enum
1421
+ {
1422
+ RuntimeEvent_Unknown = 0 ,
1423
+ RuntimeEvent_Started = 1 ,
1424
+ RuntimeEvent_Continue = 2 ,
1425
+ } RuntimeEvent;
1426
+
1427
+ static
1428
+ int
1429
+ OpenPipe (const char * name, int mode)
1430
+ {
1431
+ int fd = -1 ;
1432
+ int flags = mode | O_NONBLOCK;
1433
+
1434
+ #if defined(FD_CLOEXEC)
1435
+ flags |= O_CLOEXEC;
1436
+ #endif
1437
+
1438
+ while (fd == -1 )
1439
+ {
1440
+ fd = open (name, flags);
1441
+ if (fd == -1 )
1442
+ {
1443
+ if (mode == O_WRONLY && errno == ENXIO)
1444
+ {
1445
+ PAL_nanosleep (PIPE_OPEN_RETRY_DELAY_NS);
1446
+ continue ;
1447
+ }
1448
+ else if (errno == EINTR)
1449
+ {
1450
+ continue ;
1451
+ }
1452
+ else
1453
+ {
1454
+ break ;
1455
+ }
1456
+ }
1457
+ }
1458
+
1459
+ if (fd != -1 )
1460
+ {
1461
+ flags = fcntl (fd, F_GETFL);
1462
+ if (flags != -1 )
1463
+ {
1464
+ flags &= ~O_NONBLOCK;
1465
+ if (fcntl (fd, F_SETFL, flags) == -1 )
1466
+ {
1467
+ close (fd);
1468
+ fd = -1 ;
1469
+ }
1470
+ }
1471
+ else
1472
+ {
1473
+ close (fd);
1474
+ fd = -1 ;
1475
+ }
1476
+ }
1477
+
1478
+ return fd;
1479
+ }
1480
+
1481
+ static
1482
+ void
1483
+ ClosePipe (int fd)
1484
+ {
1485
+ if (fd != -1 )
1486
+ {
1487
+ while (close (fd) < 0 && errno == EINTR);
1488
+ }
1489
+ }
1490
+
1491
+ static
1492
+ RuntimeEventsOverPipes
1493
+ NotifyRuntimeUsingPipes ()
1494
+ {
1495
+ RuntimeEventsOverPipes result = RuntimeEventsOverPipes_Disabled;
1496
+ char startupPipeName[MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH];
1497
+ char continuePipeName[MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH];
1498
+ int startupPipeFd = -1 ;
1499
+ int continuePipeFd = -1 ;
1500
+ size_t offset = 0 ;
1501
+
1502
+ LPCSTR applicationGroupId = PAL_GetApplicationGroupId ();
1503
+
1504
+ PAL_GetTransportPipeName (continuePipeName, gPID , applicationGroupId, RuntimeContinuePipeName);
1505
+ TRACE (" NotifyRuntimeUsingPipes: opening continue '%s' pipe\n " , continuePipeName);
1506
+
1507
+ continuePipeFd = OpenPipe (continuePipeName, O_RDONLY);
1508
+ if (continuePipeFd == -1 )
1509
+ {
1510
+ if (errno == ENOENT || errno == EACCES)
1511
+ {
1512
+ TRACE (" NotifyRuntimeUsingPipes: pipe %s not found/accessible, runtime events over pipes disabled\n " , continuePipeName);
1513
+ }
1514
+ else
1515
+ {
1516
+ TRACE (" NotifyRuntimeUsingPipes: open(%s) failed: %d (%s)\n " , continuePipeName, errno, strerror (errno));
1517
+ result = RuntimeEventsOverPipes_Failed;
1518
+ }
1519
+
1520
+ goto exit;
1521
+ }
1522
+
1523
+ PAL_GetTransportPipeName (startupPipeName, gPID , applicationGroupId, RuntimeStartupPipeName);
1524
+ TRACE (" NotifyRuntimeUsingPipes: opening startup '%s' pipe\n " , startupPipeName);
1525
+
1526
+ startupPipeFd = OpenPipe (startupPipeName, O_WRONLY);
1527
+ if (startupPipeFd == -1 )
1528
+ {
1529
+ if (errno == ENOENT || errno == EACCES)
1530
+ {
1531
+ TRACE (" NotifyRuntimeUsingPipes: pipe %s not found/accessible, runtime events over pipes disabled\n " , startupPipeName);
1532
+ }
1533
+ else
1534
+ {
1535
+ TRACE (" NotifyRuntimeUsingPipes: open(%s) failed: %d (%s)\n " , startupPipeName, errno, strerror (errno));
1536
+ result = RuntimeEventsOverPipes_Failed;
1537
+ }
1538
+
1539
+ goto exit;
1540
+ }
1541
+
1542
+ TRACE (" NotifyRuntimeUsingPipes: sending started event\n " );
1543
+
1544
+ {
1545
+ unsigned char event = (unsigned char )RuntimeEvent_Started;
1546
+ unsigned char *buffer = &event;
1547
+ int bytesToWrite = sizeof (event);
1548
+ int bytesWritten = 0 ;
1549
+
1550
+ do
1551
+ {
1552
+ bytesWritten = write (startupPipeFd, buffer + offset, bytesToWrite - offset);
1553
+ if (bytesWritten > 0 )
1554
+ {
1555
+ offset += bytesWritten;
1556
+ }
1557
+ }
1558
+ while ((bytesWritten > 0 && offset < bytesToWrite) || (bytesWritten == -1 && errno == EINTR));
1559
+
1560
+ if (offset != bytesToWrite)
1561
+ {
1562
+ TRACE (" NotifyRuntimeUsingPipes: write(%s) failed: %d (%s)\n " , startupPipeName, errno, strerror (errno));
1563
+ goto exit;
1564
+ }
1565
+ }
1566
+
1567
+ TRACE (" NotifyRuntimeUsingPipes: waiting on continue event\n " );
1568
+
1569
+ {
1570
+ unsigned char event = (unsigned char )RuntimeEvent_Unknown;
1571
+ unsigned char *buffer = &event;
1572
+ int bytesToRead = sizeof (event);
1573
+ int bytesRead = 0 ;
1574
+
1575
+ offset = 0 ;
1576
+ do
1577
+ {
1578
+ bytesRead = read (continuePipeFd, buffer + offset, bytesToRead - offset);
1579
+ if (bytesRead > 0 )
1580
+ {
1581
+ offset += bytesRead;
1582
+ }
1583
+ }
1584
+ while ((bytesRead > 0 && offset < bytesToRead) || (bytesRead == -1 && errno == EINTR));
1585
+
1586
+ if (offset == bytesToRead && event == (unsigned char )RuntimeEvent_Continue)
1587
+ {
1588
+ TRACE (" NotifyRuntimeUsingPipes: received continue event\n " );
1589
+ }
1590
+ else
1591
+ {
1592
+ TRACE (" NotifyRuntimeUsingPipes: received invalid event\n " );
1593
+ goto exit;
1594
+ }
1595
+ }
1596
+
1597
+ result = RuntimeEventsOverPipes_Succeeded;
1598
+
1599
+ exit:
1600
+
1601
+ if (startupPipeFd != -1 )
1602
+ {
1603
+ ClosePipe (startupPipeFd);
1604
+ }
1605
+
1606
+ if (continuePipeFd != -1 )
1607
+ {
1608
+ ClosePipe (continuePipeFd);
1609
+ }
1610
+
1611
+ return result;
1612
+ }
1613
+ #endif // ENABLE_RUNTIME_EVENTS_OVER_PIPES
1614
+
1615
+ static
1416
1616
BOOL
1417
- PALAPI
1418
- PAL_NotifyRuntimeStarted ()
1617
+ NotifyRuntimeUsingSemaphores ()
1419
1618
{
1420
1619
char startupSemName[CLR_SEM_MAX_NAMELEN];
1421
1620
char continueSemName[CLR_SEM_MAX_NAMELEN];
@@ -1436,13 +1635,13 @@ PAL_NotifyRuntimeStarted()
1436
1635
CreateSemaphoreName (startupSemName, RuntimeStartupSemaphoreName, unambiguousProcessDescriptor, applicationGroupId);
1437
1636
CreateSemaphoreName (continueSemName, RuntimeContinueSemaphoreName, unambiguousProcessDescriptor, applicationGroupId);
1438
1637
1439
- TRACE (" PAL_NotifyRuntimeStarted opening continue '%s' startup '%s'\n " , continueSemName, startupSemName);
1638
+ TRACE (" NotifyRuntimeUsingSemaphores: opening continue '%s' startup '%s'\n " , continueSemName, startupSemName);
1440
1639
1441
1640
// Open the debugger startup semaphore. If it doesn't exists, then we do nothing and return
1442
1641
startupSem = sem_open (startupSemName, 0 );
1443
1642
if (startupSem == SEM_FAILED)
1444
1643
{
1445
- TRACE (" sem_open(%s) failed: %d (%s)\n " , startupSemName, errno, strerror (errno));
1644
+ TRACE (" NotifyRuntimeUsingSemaphores: sem_open(%s) failed: %d (%s)\n " , startupSemName, errno, strerror (errno));
1446
1645
goto exit;
1447
1646
}
1448
1647
@@ -1465,7 +1664,7 @@ PAL_NotifyRuntimeStarted()
1465
1664
{
1466
1665
if (EINTR == errno)
1467
1666
{
1468
- TRACE (" sem_wait() failed with EINTR; re-waiting" );
1667
+ TRACE (" NotifyRuntimeUsingSemaphores: sem_wait() failed with EINTR; re-waiting" );
1469
1668
continue ;
1470
1669
}
1471
1670
ASSERT (" sem_wait(continueSem) failed: errno is %d (%s)\n " , errno, strerror (errno));
@@ -1487,6 +1686,45 @@ PAL_NotifyRuntimeStarted()
1487
1686
return launched;
1488
1687
}
1489
1688
1689
+ /* ++
1690
+ PAL_NotifyRuntimeStarted
1691
+
1692
+ Signals the debugger waiting for runtime startup notification to continue and
1693
+ waits until the debugger signals us to continue.
1694
+
1695
+ Parameters:
1696
+ None
1697
+
1698
+ Return value:
1699
+ TRUE - successfully launched by debugger, FALSE - not launched or some failure in the handshake
1700
+ --*/
1701
+ BOOL
1702
+ PALAPI
1703
+ PAL_NotifyRuntimeStarted ()
1704
+ {
1705
+ #ifdef ENABLE_RUNTIME_EVENTS_OVER_PIPES
1706
+ // Test pipes as runtime event transport.
1707
+ RuntimeEventsOverPipes result = NotifyRuntimeUsingPipes ();
1708
+ switch (result)
1709
+ {
1710
+ case RuntimeEventsOverPipes_Disabled:
1711
+ TRACE (" PAL_NotifyRuntimeStarted: pipe handshake disabled, try semaphores\n " );
1712
+ return NotifyRuntimeUsingSemaphores ();
1713
+ case RuntimeEventsOverPipes_Failed:
1714
+ TRACE (" PAL_NotifyRuntimeStarted: pipe handshake failed\n " );
1715
+ return FALSE ;
1716
+ case RuntimeEventsOverPipes_Succeeded:
1717
+ TRACE (" PAL_NotifyRuntimeStarted: pipe handshake succeeded\n " );
1718
+ return TRUE ;
1719
+ default :
1720
+ // Unexpected result.
1721
+ return FALSE ;
1722
+ }
1723
+ #else
1724
+ return NotifyRuntimeUsingSemaphores ();
1725
+ #endif // ENABLE_RUNTIME_EVENTS_OVER_PIPES
1726
+ }
1727
+
1490
1728
LPCSTR
1491
1729
PALAPI
1492
1730
PAL_GetApplicationGroupId ()
0 commit comments