@@ -105,6 +105,9 @@ extern "C"
105
105
} \
106
106
} while (false )
107
107
108
+ // On macOS 26, sem_open fails if debugger and debugee are signed with different team ids.
109
+ // Use fifos instead of semaphores to avoid this issue, https://github.com/dotnet/runtime/issues/116545
110
+ #define ENABLE_RUNTIME_EVENTS_OVER_PIPES
108
111
#endif // __APPLE__
109
112
110
113
#ifdef __NetBSD__
@@ -1432,21 +1435,217 @@ static uint64_t HashSemaphoreName(uint64_t a, uint64_t b)
1432
1435
static const char *const TwoWayNamedPipePrefix = " clr-debug-pipe" ;
1433
1436
static const char * IpcNameFormat = " %s-%d-%llu-%s" ;
1434
1437
1435
- /* ++
1436
- PAL_NotifyRuntimeStarted
1438
+ #ifdef ENABLE_RUNTIME_EVENTS_OVER_PIPES
1439
+ static const char * RuntimeStartupPipeName = " st" ;
1440
+ static const char * RuntimeContinuePipeName = " co" ;
1437
1441
1438
- Signals the debugger waiting for runtime startup notification to continue and
1439
- waits until the debugger signals us to continue.
1442
+ #define PIPE_OPEN_RETRY_DELAY_NS 500000000 // 500 ms
1440
1443
1441
- Parameters:
1442
- None
1444
+ typedef enum
1445
+ {
1446
+ RuntimeEventsOverPipes_Disabled = 0 ,
1447
+ RuntimeEventsOverPipes_Succeeded = 1 ,
1448
+ RuntimeEventsOverPipes_Failed = 2 ,
1449
+ } RuntimeEventsOverPipes;
1443
1450
1444
- Return value:
1445
- TRUE - successfully launched by debugger, FALSE - not launched or some failure in the handshake
1446
- --*/
1451
+ typedef enum
1452
+ {
1453
+ RuntimeEvent_Unknown = 0 ,
1454
+ RuntimeEvent_Started = 1 ,
1455
+ RuntimeEvent_Continue = 2 ,
1456
+ } RuntimeEvent;
1457
+
1458
+ static
1459
+ int
1460
+ OpenPipe (const char * name, int mode)
1461
+ {
1462
+ int fd = -1 ;
1463
+ int flags = mode | O_NONBLOCK;
1464
+
1465
+ #if defined(FD_CLOEXEC)
1466
+ flags |= O_CLOEXEC;
1467
+ #endif
1468
+
1469
+ while (fd == -1 )
1470
+ {
1471
+ fd = open (name, flags);
1472
+ if (fd == -1 )
1473
+ {
1474
+ if (mode == O_WRONLY && errno == ENXIO)
1475
+ {
1476
+ PAL_nanosleep (PIPE_OPEN_RETRY_DELAY_NS);
1477
+ continue ;
1478
+ }
1479
+ else if (errno == EINTR)
1480
+ {
1481
+ continue ;
1482
+ }
1483
+ else
1484
+ {
1485
+ break ;
1486
+ }
1487
+ }
1488
+ }
1489
+
1490
+ if (fd != -1 )
1491
+ {
1492
+ flags = fcntl (fd, F_GETFL);
1493
+ if (flags != -1 )
1494
+ {
1495
+ flags &= ~O_NONBLOCK;
1496
+ if (fcntl (fd, F_SETFL, flags) == -1 )
1497
+ {
1498
+ close (fd);
1499
+ fd = -1 ;
1500
+ }
1501
+ }
1502
+ else
1503
+ {
1504
+ close (fd);
1505
+ fd = -1 ;
1506
+ }
1507
+ }
1508
+
1509
+ return fd;
1510
+ }
1511
+
1512
+ static
1513
+ void
1514
+ ClosePipe (int fd)
1515
+ {
1516
+ if (fd != -1 )
1517
+ {
1518
+ while (close (fd) < 0 && errno == EINTR);
1519
+ }
1520
+ }
1521
+
1522
+ static
1523
+ RuntimeEventsOverPipes
1524
+ NotifyRuntimeUsingPipes ()
1525
+ {
1526
+ RuntimeEventsOverPipes result = RuntimeEventsOverPipes_Disabled;
1527
+ char startupPipeName[MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH];
1528
+ char continuePipeName[MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH];
1529
+ int startupPipeFd = -1 ;
1530
+ int continuePipeFd = -1 ;
1531
+ size_t offset = 0 ;
1532
+
1533
+ LPCSTR applicationGroupId = PAL_GetApplicationGroupId ();
1534
+
1535
+ PAL_GetTransportPipeName (continuePipeName, gPID , applicationGroupId, RuntimeContinuePipeName);
1536
+ TRACE (" NotifyRuntimeUsingPipes: opening continue '%s' pipe\n " , continuePipeName);
1537
+
1538
+ continuePipeFd = OpenPipe (continuePipeName, O_RDONLY);
1539
+ if (continuePipeFd == -1 )
1540
+ {
1541
+ if (errno == ENOENT || errno == EACCES)
1542
+ {
1543
+ TRACE (" NotifyRuntimeUsingPipes: pipe %s not found/accessible, runtime events over pipes disabled\n " , continuePipeName);
1544
+ }
1545
+ else
1546
+ {
1547
+ TRACE (" NotifyRuntimeUsingPipes: open(%s) failed: %d (%s)\n " , continuePipeName, errno, strerror (errno));
1548
+ result = RuntimeEventsOverPipes_Failed;
1549
+ }
1550
+
1551
+ goto exit;
1552
+ }
1553
+
1554
+ PAL_GetTransportPipeName (startupPipeName, gPID , applicationGroupId, RuntimeStartupPipeName);
1555
+ TRACE (" NotifyRuntimeUsingPipes: opening startup '%s' pipe\n " , startupPipeName);
1556
+
1557
+ startupPipeFd = OpenPipe (startupPipeName, O_WRONLY);
1558
+ if (startupPipeFd == -1 )
1559
+ {
1560
+ if (errno == ENOENT || errno == EACCES)
1561
+ {
1562
+ TRACE (" NotifyRuntimeUsingPipes: pipe %s not found/accessible, runtime events over pipes disabled\n " , startupPipeName);
1563
+ }
1564
+ else
1565
+ {
1566
+ TRACE (" NotifyRuntimeUsingPipes: open(%s) failed: %d (%s)\n " , startupPipeName, errno, strerror (errno));
1567
+ result = RuntimeEventsOverPipes_Failed;
1568
+ }
1569
+
1570
+ goto exit;
1571
+ }
1572
+
1573
+ TRACE (" NotifyRuntimeUsingPipes: sending started event\n " );
1574
+
1575
+ {
1576
+ unsigned char event = (unsigned char )RuntimeEvent_Started;
1577
+ unsigned char *buffer = &event;
1578
+ int bytesToWrite = sizeof (event);
1579
+ int bytesWritten = 0 ;
1580
+
1581
+ do
1582
+ {
1583
+ bytesWritten = write (startupPipeFd, buffer + offset, bytesToWrite - offset);
1584
+ if (bytesWritten > 0 )
1585
+ {
1586
+ offset += bytesWritten;
1587
+ }
1588
+ }
1589
+ while ((bytesWritten > 0 && offset < bytesToWrite) || (bytesWritten == -1 && errno == EINTR));
1590
+
1591
+ if (offset != bytesToWrite)
1592
+ {
1593
+ TRACE (" NotifyRuntimeUsingPipes: write(%s) failed: %d (%s)\n " , startupPipeName, errno, strerror (errno));
1594
+ goto exit;
1595
+ }
1596
+ }
1597
+
1598
+ TRACE (" NotifyRuntimeUsingPipes: waiting on continue event\n " );
1599
+
1600
+ {
1601
+ unsigned char event = (unsigned char )RuntimeEvent_Unknown;
1602
+ unsigned char *buffer = &event;
1603
+ int bytesToRead = sizeof (event);
1604
+ int bytesRead = 0 ;
1605
+
1606
+ offset = 0 ;
1607
+ do
1608
+ {
1609
+ bytesRead = read (continuePipeFd, buffer + offset, bytesToRead - offset);
1610
+ if (bytesRead > 0 )
1611
+ {
1612
+ offset += bytesRead;
1613
+ }
1614
+ }
1615
+ while ((bytesRead > 0 && offset < bytesToRead) || (bytesRead == -1 && errno == EINTR));
1616
+
1617
+ if (offset == bytesToRead && event == (unsigned char )RuntimeEvent_Continue)
1618
+ {
1619
+ TRACE (" NotifyRuntimeUsingPipes: received continue event\n " );
1620
+ }
1621
+ else
1622
+ {
1623
+ TRACE (" NotifyRuntimeUsingPipes: received invalid event\n " );
1624
+ goto exit;
1625
+ }
1626
+ }
1627
+
1628
+ result = RuntimeEventsOverPipes_Succeeded;
1629
+
1630
+ exit:
1631
+
1632
+ if (startupPipeFd != -1 )
1633
+ {
1634
+ ClosePipe (startupPipeFd);
1635
+ }
1636
+
1637
+ if (continuePipeFd != -1 )
1638
+ {
1639
+ ClosePipe (continuePipeFd);
1640
+ }
1641
+
1642
+ return result;
1643
+ }
1644
+ #endif // ENABLE_RUNTIME_EVENTS_OVER_PIPES
1645
+
1646
+ static
1447
1647
BOOL
1448
- PALAPI
1449
- PAL_NotifyRuntimeStarted ()
1648
+ NotifyRuntimeUsingSemaphores ()
1450
1649
{
1451
1650
char startupSemName[CLR_SEM_MAX_NAMELEN];
1452
1651
char continueSemName[CLR_SEM_MAX_NAMELEN];
@@ -1467,13 +1666,13 @@ PAL_NotifyRuntimeStarted()
1467
1666
CreateSemaphoreName (startupSemName, RuntimeStartupSemaphoreName, unambiguousProcessDescriptor, applicationGroupId);
1468
1667
CreateSemaphoreName (continueSemName, RuntimeContinueSemaphoreName, unambiguousProcessDescriptor, applicationGroupId);
1469
1668
1470
- TRACE (" PAL_NotifyRuntimeStarted opening continue '%s' startup '%s'\n " , continueSemName, startupSemName);
1669
+ TRACE (" NotifyRuntimeUsingSemaphores: opening continue '%s' startup '%s'\n " , continueSemName, startupSemName);
1471
1670
1472
1671
// Open the debugger startup semaphore. If it doesn't exists, then we do nothing and return
1473
1672
startupSem = sem_open (startupSemName, 0 );
1474
1673
if (startupSem == SEM_FAILED)
1475
1674
{
1476
- TRACE (" sem_open(%s) failed: %d (%s)\n " , startupSemName, errno, strerror (errno));
1675
+ TRACE (" NotifyRuntimeUsingSemaphores: sem_open(%s) failed: %d (%s)\n " , startupSemName, errno, strerror (errno));
1477
1676
goto exit;
1478
1677
}
1479
1678
@@ -1496,7 +1695,7 @@ PAL_NotifyRuntimeStarted()
1496
1695
{
1497
1696
if (EINTR == errno)
1498
1697
{
1499
- TRACE (" sem_wait() failed with EINTR; re-waiting" );
1698
+ TRACE (" NotifyRuntimeUsingSemaphores: sem_wait() failed with EINTR; re-waiting" );
1500
1699
continue ;
1501
1700
}
1502
1701
ASSERT (" sem_wait(continueSem) failed: errno is %d (%s)\n " , errno, strerror (errno));
@@ -1518,6 +1717,45 @@ PAL_NotifyRuntimeStarted()
1518
1717
return launched;
1519
1718
}
1520
1719
1720
+ /* ++
1721
+ PAL_NotifyRuntimeStarted
1722
+
1723
+ Signals the debugger waiting for runtime startup notification to continue and
1724
+ waits until the debugger signals us to continue.
1725
+
1726
+ Parameters:
1727
+ None
1728
+
1729
+ Return value:
1730
+ TRUE - successfully launched by debugger, FALSE - not launched or some failure in the handshake
1731
+ --*/
1732
+ BOOL
1733
+ PALAPI
1734
+ PAL_NotifyRuntimeStarted ()
1735
+ {
1736
+ #ifdef ENABLE_RUNTIME_EVENTS_OVER_PIPES
1737
+ // Test pipes as runtime event transport.
1738
+ RuntimeEventsOverPipes result = NotifyRuntimeUsingPipes ();
1739
+ switch (result)
1740
+ {
1741
+ case RuntimeEventsOverPipes_Disabled:
1742
+ TRACE (" PAL_NotifyRuntimeStarted: pipe handshake disabled, try semaphores\n " );
1743
+ return NotifyRuntimeUsingSemaphores ();
1744
+ case RuntimeEventsOverPipes_Failed:
1745
+ TRACE (" PAL_NotifyRuntimeStarted: pipe handshake failed\n " );
1746
+ return FALSE ;
1747
+ case RuntimeEventsOverPipes_Succeeded:
1748
+ TRACE (" PAL_NotifyRuntimeStarted: pipe handshake succeeded\n " );
1749
+ return TRUE ;
1750
+ default :
1751
+ // Unexpected result.
1752
+ return FALSE ;
1753
+ }
1754
+ #else
1755
+ return NotifyRuntimeUsingSemaphores ();
1756
+ #endif // ENABLE_RUNTIME_EVENTS_OVER_PIPES
1757
+ }
1758
+
1521
1759
LPCSTR
1522
1760
PALAPI
1523
1761
PAL_GetApplicationGroupId ()
0 commit comments