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