Skip to content

Commit 415a415

Browse files
authored
zend_call_stack.c: AIX backend (#22906)
Uses pthread_getthrds_np (so requires pthread linked, by default on ZTS, needs to be added for NTS). The stack size part is weird, but works in testing. An alternative approach is using procfs, but I didn't bother with this due to it not working on PASE (and the pthread approach works for the main thread too).
1 parent dfba0e8 commit 415a415

4 files changed

Lines changed: 109 additions & 1 deletion

File tree

Zend/Zend.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ AC_CHECK_FUNCS(m4_normalize([
148148
pthread_attr_getstack
149149
pthread_get_stackaddr_np
150150
pthread_getattr_np
151+
pthread_getthrds_np
151152
pthread_stackseg_np
152153
strnlen
153154
]))

Zend/tests/stack_limit/stack_limit_010.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Stack limit 010 - Check stack size detection against known defaults
44
zend_test
55
--SKIPIF--
66
<?php
7+
if (PHP_OS_FAMILY == "AIX") {
8+
die("skip AIX adjusts top of stack (used for size) in unpredictable way");
9+
}
710
if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_call_stack_get() is not available");
811
if (!getenv('STACK_LIMIT_DEFAULTS_CHECK')) { die('skip STACK_LIMIT_DEFAULTS_CHECK not set'); }
912
?>

Zend/zend_call_stack.c

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
#endif /* ZEND_WIN32 */
3737
#if (defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)) || \
3838
defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || \
39-
defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun)
39+
defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun) || \
40+
defined(_AIX)
4041
# include <pthread.h>
4142
#endif
4243
#if defined(__FreeBSD__) || defined(__DragonFly__)
@@ -788,6 +789,79 @@ static bool zend_call_stack_get_solaris(zend_call_stack *stack)
788789
}
789790
#endif /* defined(__sun) */
790791

792+
#if defined(_AIX)
793+
static bool zend_call_stack_get_aix_pthread(zend_call_stack *stack)
794+
{
795+
#ifdef HAVE_PTHREAD_GETTHRDS_NP
796+
pthread_t pt = pthread_self();
797+
struct __pthrdsinfo thread_info = {0};
798+
/*
799+
* We don't need the register buffer since we only call the function
800+
* on our own thread, and since the register buffer is only used for
801+
* suspended threads...
802+
*/
803+
int regsz = 0;
804+
805+
if (pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_ALL, &thread_info,
806+
sizeof(thread_info), NULL, &regsz)) {
807+
return false;
808+
}
809+
810+
/*
811+
* These can be null in rare situations, allegedly with user-provided
812+
* stacks with pthread (according to OpenJDK)
813+
*/
814+
if (!(thread_info.__pi_stackend && thread_info.__pi_stackaddr)) {
815+
return false;
816+
}
817+
818+
/*
819+
* The top of the stack (stackend) is not page aligned, there's some
820+
* internal stuff above it. Thankfully, we don't need page alignment.
821+
*
822+
* The size is a little weird. The stacksize field for child threads
823+
* is smaller than subtracting the bottom (stackaddr) from the top;
824+
* it's about 0x888 to 0x1888 above stackaddr. I'm assuming it rounds
825+
* the bottom of the stack to page alignment? The main thread size is
826+
* the same as end - addr, but it is variable between systems; also
827+
* assuming there's stuff at the top of the stack that gets taken off,
828+
* regardless of maximum declared size.
829+
*
830+
* A somewhat crude diagram is available here:
831+
* https://www.ibm.com/docs/en/aix/7.2.0?topic=tuning-thread-environment-variables
832+
*
833+
* pthread->pt_stk.st_limit is __pi_stackend,
834+
* above that is internal pthread junk close to the end of page
835+
* pthread->pt_stk.st_base is __pi_stackaddr,
836+
* below that is the red zone
837+
*/
838+
stack->base = thread_info.__pi_stackend;
839+
stack->max_size = thread_info.__pi_stackend - thread_info.__pi_stackaddr;
840+
return true;
841+
#else
842+
/* pthread likely not linked in; default NTS build behaviour */
843+
return false;
844+
#endif
845+
}
846+
847+
static bool zend_call_stack_get_aix(zend_call_stack *stack)
848+
{
849+
/*
850+
* While we could use /proc on AIX (and the implementation basically
851+
* like the Solaris one, as the procfs is similar), it doesn't work on
852+
* PASE. The pthread API works even on the main thread, so we should
853+
* use it when we have pthread linked (always with ZTS, maybe not with
854+
* NTS builds).
855+
*/
856+
return zend_call_stack_get_aix_pthread(stack);
857+
}
858+
#else
859+
static bool zend_call_stack_get_aix(zend_call_stack *stack)
860+
{
861+
return false;
862+
}
863+
#endif /* defined(_AIX) */
864+
791865
/** Get the stack information for the calling thread */
792866
ZEND_API bool zend_call_stack_get(zend_call_stack *stack)
793867
{
@@ -823,6 +897,10 @@ ZEND_API bool zend_call_stack_get(zend_call_stack *stack)
823897
return true;
824898
}
825899

900+
if (zend_call_stack_get_aix(stack)) {
901+
return true;
902+
}
903+
826904
return false;
827905
}
828906

Zend/zend_call_stack.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,32 @@ static inline size_t zend_call_stack_default_size(void)
101101
#ifdef __sun
102102
return 8 * 4096;
103103
#endif
104+
#ifdef _AIX
105+
/*
106+
* default pthread stack limit is 96 KB on 32-bit, 192 KB on 64-bit
107+
* https://www.ibm.com/docs/en/aix/7.1.0?topic=programming-threads-library-options
108+
*/
109+
#ifdef HAVE_PTHREAD_GETTHRDS_NP /* if we have pthread linked (not in libc) */
110+
if (pthread_self() != 1) {
111+
#ifdef __64BIT__
112+
return 192 * 1024;
113+
#else
114+
return 96 * 1024;
115+
#endif
116+
}
117+
#endif
118+
/*
119+
* default AIX ulimit -s value is allegedly 32 MB, default values per:
120+
* https://www.ibm.com/docs/en/aix/7.1.0?topic=u-ulimit-command
121+
* N.B.: the the file uses 512b blocks, but the command uses kilobytes
122+
* https://www.ibm.com/support/pages/ibm-aix-security-ulimit-and-ulimit-d-output-differs-value-etcsecuritylimits
123+
*
124+
* note PASE uses an unlimited stack size by default, which is capped
125+
* at the PowerPC segment size (256 MB)
126+
*/
127+
return 32 * 1024 * 1024;
128+
#endif
129+
104130

105131
return 2 * 1024 * 1024;
106132
}

0 commit comments

Comments
 (0)