Skip to content

Commit bffdf56

Browse files
authored
Merge pull request #409 from pmodels/mdorier/add-ABT_thread_get_stack
thread: added ABT_thread_get_stack
2 parents 6e21abc + c70cfff commit bffdf56

File tree

4 files changed

+195
-0
lines changed

4 files changed

+195
-0
lines changed

src/include/abt.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2512,6 +2512,7 @@ int ABT_thread_is_unnamed(ABT_thread thread, ABT_bool *is_unnamed) ABT_API_PUBLI
25122512
int ABT_thread_equal(ABT_thread thread1, ABT_thread thread2, ABT_bool *result)
25132513
ABT_API_PUBLIC;
25142514
int ABT_thread_get_stacksize(ABT_thread thread, size_t *stacksize) ABT_API_PUBLIC;
2515+
int ABT_thread_get_stack(ABT_thread thread, void **stackaddr, size_t *stacksize) ABT_API_PUBLIC;
25152516
int ABT_thread_get_id(ABT_thread thread, ABT_unit_id *thread_id) ABT_API_PUBLIC;
25162517
int ABT_thread_set_arg(ABT_thread thread, void *arg) ABT_API_PUBLIC;
25172518
int ABT_thread_get_arg(ABT_thread thread, void **arg) ABT_API_PUBLIC;

src/thread.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2178,6 +2178,69 @@ int ABT_thread_get_stacksize(ABT_thread thread, size_t *stacksize)
21782178
return ABT_SUCCESS;
21792179
}
21802180

2181+
/**
2182+
* @ingroup ULT
2183+
* @brief Get stack address and size of a work unit.
2184+
*
2185+
* \c ABT_thread_get_stack() returns the stack address and stack size of the
2186+
* work unit \c thread through \c stackaddr and \c stacksize. If \c thread
2187+
* does not have a stack managed by the Argobots runtime (e.g., a tasklet or
2188+
* the primary ULT), both \c stackaddr and \c stacksize are set to 0 and NULL,
2189+
* respectively.
2190+
*
2191+
* Either \c stackaddr or \c stacksize may be \c NULL. In this case, the
2192+
* corresponding value is not returned.
2193+
*
2194+
* @note
2195+
* This function directly accesses the stack information without allocating
2196+
* a thread attribute object, making it more efficient than using
2197+
* \c ABT_thread_get_attr() followed by \c ABT_thread_attr_get_stack().
2198+
*
2199+
* @contexts
2200+
* \DOC_CONTEXT_INIT \DOC_CONTEXT_NOCTXSWITCH
2201+
*
2202+
* @errors
2203+
* \DOC_ERROR_SUCCESS
2204+
* \DOC_ERROR_INV_THREAD_HANDLE{\c thread}
2205+
*
2206+
* @undefined
2207+
* \DOC_UNDEFINED_UNINIT
2208+
*
2209+
* @param[in] thread work unit handle
2210+
* @param[out] stackaddr stack address (base of stack)
2211+
* @param[out] stacksize stack size in bytes
2212+
* @return Error code
2213+
*/
2214+
int ABT_thread_get_stack(ABT_thread thread, void **stackaddr, size_t *stacksize)
2215+
{
2216+
ABTI_UB_ASSERT(ABTI_initialized());
2217+
2218+
ABTI_thread *p_thread = ABTI_thread_get_ptr(thread);
2219+
ABTI_CHECK_NULL_THREAD_PTR(p_thread);
2220+
ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread);
2221+
2222+
if (p_ythread) {
2223+
void *p_stacktop = ABTD_ythread_context_get_stacktop(&p_ythread->ctx);
2224+
size_t size = ABTD_ythread_context_get_stacksize(&p_ythread->ctx);
2225+
if (stackaddr) {
2226+
if (p_stacktop) {
2227+
*stackaddr = (void *)(((char *)p_stacktop) - size);
2228+
} else {
2229+
*stackaddr = NULL;
2230+
}
2231+
}
2232+
if (stacksize) {
2233+
*stacksize = size;
2234+
}
2235+
} else {
2236+
if (stackaddr)
2237+
*stackaddr = NULL;
2238+
if (stacksize)
2239+
*stacksize = 0;
2240+
}
2241+
return ABT_SUCCESS;
2242+
}
2243+
21812244
/**
21822245
* @ingroup ULT
21832246
* @brief Get ID of a work unit

test/basic/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ TESTS = \
3030
thread_data \
3131
thread_data2 \
3232
thread_id \
33+
thread_get_stack \
3334
task_create \
3435
task_create_on_xstream \
3536
task_revive \
@@ -138,6 +139,7 @@ thread_migrate_SOURCES = thread_migrate.c
138139
thread_data_SOURCES = thread_data.c
139140
thread_data2_SOURCES = thread_data2.c
140141
thread_id_SOURCES = thread_id.c
142+
thread_get_stack_SOURCES = thread_get_stack.c
141143
task_create_SOURCES = task_create.c
142144
task_create_on_xstream_SOURCES = task_create_on_xstream.c
143145
task_revive_SOURCES = task_revive.c

test/basic/thread_get_stack.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2+
/*
3+
* See COPYRIGHT in top-level directory.
4+
*/
5+
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include "abt.h"
9+
#include "abttest.h"
10+
11+
#define DEFAULT_NUM_THREADS 4
12+
13+
void thread_func(void *arg)
14+
{
15+
int ret;
16+
void *stackaddr1 = NULL, *stackaddr2 = NULL;
17+
size_t stacksize1 = 0, stacksize2 = 0;
18+
ABT_thread self;
19+
ABT_thread_attr attr;
20+
21+
/* Get self */
22+
ret = ABT_thread_self(&self);
23+
ATS_ERROR(ret, "ABT_thread_self");
24+
25+
/* Method 1: New direct API */
26+
ret = ABT_thread_get_stack(self, &stackaddr1, &stacksize1);
27+
ATS_ERROR(ret, "ABT_thread_get_stack");
28+
29+
/* Method 2: Old method via attributes (for comparison) */
30+
ret = ABT_thread_get_attr(self, &attr);
31+
ATS_ERROR(ret, "ABT_thread_get_attr");
32+
33+
ret = ABT_thread_attr_get_stack(attr, &stackaddr2, &stacksize2);
34+
ATS_ERROR(ret, "ABT_thread_attr_get_stack");
35+
36+
ret = ABT_thread_attr_free(&attr);
37+
ATS_ERROR(ret, "ABT_thread_attr_free");
38+
39+
/* Verify both methods return the same values */
40+
if (stackaddr1 != stackaddr2) {
41+
ATS_ERROR(ABT_ERR_OTHER, "Stack addresses don't match");
42+
}
43+
if (stacksize1 != stacksize2) {
44+
ATS_ERROR(ABT_ERR_OTHER, "Stack sizes don't match");
45+
}
46+
47+
ATS_printf(2, "Thread: stackaddr=%p, stacksize=%zu\n", stackaddr1,
48+
stacksize1);
49+
50+
/* Test partial queries */
51+
void *stackaddr_only = NULL;
52+
ret = ABT_thread_get_stack(self, &stackaddr_only, NULL);
53+
ATS_ERROR(ret, "ABT_thread_get_stack (addr only)");
54+
if (stackaddr_only != stackaddr1) {
55+
ATS_ERROR(ABT_ERR_OTHER, "Stackaddr-only query mismatch");
56+
}
57+
58+
size_t stacksize_only = 0;
59+
ret = ABT_thread_get_stack(self, NULL, &stacksize_only);
60+
ATS_ERROR(ret, "ABT_thread_get_stack (size only)");
61+
if (stacksize_only != stacksize1) {
62+
ATS_ERROR(ABT_ERR_OTHER, "Stacksize-only query mismatch");
63+
}
64+
}
65+
66+
int main(int argc, char *argv[])
67+
{
68+
int ret, i;
69+
int num_threads = DEFAULT_NUM_THREADS;
70+
ABT_xstream xstream;
71+
ABT_pool pool;
72+
ABT_thread *threads;
73+
74+
/* Initialize */
75+
ATS_read_args(argc, argv);
76+
if (argc > 1) {
77+
num_threads = ATS_get_arg_val(ATS_ARG_N_ULT);
78+
}
79+
ATS_init(argc, argv, 1);
80+
81+
ATS_printf(1, "# of ULTs: %d\n", num_threads);
82+
83+
threads = (ABT_thread *)malloc(num_threads * sizeof(ABT_thread));
84+
85+
/* Get the primary execution stream */
86+
ret = ABT_xstream_self(&xstream);
87+
ATS_ERROR(ret, "ABT_xstream_self");
88+
89+
/* Get the pool */
90+
ret = ABT_xstream_get_main_pools(xstream, 1, &pool);
91+
ATS_ERROR(ret, "ABT_xstream_get_main_pools");
92+
93+
/* Create ULTs */
94+
for (i = 0; i < num_threads; i++) {
95+
ret = ABT_thread_create(pool, thread_func, NULL, ABT_THREAD_ATTR_NULL,
96+
&threads[i]);
97+
ATS_ERROR(ret, "ABT_thread_create");
98+
}
99+
100+
/* Join and free ULTs */
101+
for (i = 0; i < num_threads; i++) {
102+
ret = ABT_thread_free(&threads[i]);
103+
ATS_ERROR(ret, "ABT_thread_free");
104+
}
105+
106+
/* Test with external thread (should return NULL/0) */
107+
void *ext_stackaddr = (void *)0xdeadbeef;
108+
size_t ext_stacksize = 12345;
109+
ABT_thread ext_thread;
110+
111+
ret = ABT_thread_self(&ext_thread);
112+
ATS_ERROR(ret, "ABT_thread_self");
113+
114+
ret = ABT_thread_get_stack(ext_thread, &ext_stackaddr, &ext_stacksize);
115+
ATS_ERROR(ret, "ABT_thread_get_stack (external)");
116+
117+
ATS_printf(2, "External thread: stackaddr=%p, stacksize=%zu\n",
118+
ext_stackaddr, ext_stacksize);
119+
120+
/* Note: External thread may have a stack or not depending on version */
121+
/* Just verify the call succeeds */
122+
123+
/* Finalize */
124+
ret = ATS_finalize(0);
125+
126+
free(threads);
127+
128+
return ret;
129+
}

0 commit comments

Comments
 (0)