-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsec_handle_mgmt.tex
583 lines (525 loc) · 24.3 KB
/
sec_handle_mgmt.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
\section{Handle Management}
Each OMPD call that is dependent on some context must provide this
context via a handle.
There are handles for address spaces, threads, parallel regions, and tasks.
Handles are guaranteed to be constant for the
duration of the construct they represent.
This section describes function interfaces for extracting
handle information from the OpenMP runtime system.
\subsection{Address Space Handles}
The debugger obtains an address space handle when it initializes
a session on a live process or core file by calling
\refdef{\texttt{ompd\_process\_initialize}}{process-initialize:def}.
On return from \verb|ompd_process_initialize| the address
space handle is owned by the debugger.
When the debugger is finished with the target address space handle it
should call \texttt{ompd\_release\_address\_space\_handle} to release
the handle and give the OMPD implementation the opportunity to release
any resources it may have related to the target.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_release_address_space_handle (
ompd_address_space_handle_t *handle /* IN */
);
\end{lstlisting}
\end{quote}
\labeldef{release-address-space-handle:def}
\subsection{Thread Handles}
\paragraph{Retrieve handles for all OpenMP threads.}
The \verb|ompd_get_threads| operation enables the debugger
to obtain pointers to handles for all OpenMP threads associated
with an address space handle.
A successful invocation of \verb|ompd_get_threads| returns
a pointer to a vector of pointers to handles in \verb|*thread_handle_vector|
and returns the number of handle pointers in \verb|*num_handles|.
This call yields meaningful results only if all OpenMP threads in
the target process are stopped;
otherwise, the OpenMP runtime may be creating and/or destroying
threads during or after the call, rendering useless the
vector of handles returned.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_threads (
ompd_address_space_handle_t *handle, /* IN */
ompd_thread_handle_t ***thread_handle_vector, /* OUT */
int *num_handles /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-threads:def}
The \texttt{num\_handles} pointer argument must be valid.
The \texttt{thread\_handle\_vector} pointer argument may be NULL,
in which case the number of handles that would have been returned
had the argument not been NULL is returned in \texttt{*num\_handles}.
This allows the debugger to find out how many OpenMP threads are
running in the address space when it is not interested in the handles
themselves.
The OMPD DLL gets the memory required for the vector of pointers to thread
handles using the memory allocation routine in the callbacks it received during
the call to \refdef{\texttt{ompd\_initialize}}{initialize:def}. If the OMPD
implementation needs to allocate heap memory for the thread handles, it must
use the callbacks to acquire this memory. On return, the vector and the thread
handles are `owned' by the debugger, and the debugger is responsible for
releasing them when they are no longer required.
The thread handles must be released by calling
\refdef{\texttt{ompd\_release\_thread\_handle}}{release-thread-handle:def}.
The vector was allocated by the OMPD implementation using the allocation
routine in the callbacks it received during
initialization (see \refdef{\texttt{ompt\_initialize}}{initialize:def});
the debugger must deallocate the vector in a compatible manner.
\paragraph{Retrieve handles for OpenMP threads in a parallel region.}
The \verb|ompd_get_thread_in_parallel| operation enables the debugger
to obtain handles for all OpenMP threads associated with a parallel region.
A successful invocation of \verb|ompd_get_thread_in_parallel|
returns a pointer to a vector of pointers to thread handles in
\verb|*thread_handle_vector|,
and returns the number of handles in \verb|*num_handles|.
This call yields meaningful results only if all OpenMP threads
in the parallel region are stopped; otherwise, the OpenMP runtime
may be creating and/or destroying threads during or after the call,
rendering useless the vector of handles returned.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_thread_in_parallel (
ompd_parallel_handle_t *parallel_handle, /* IN */
ompd_thread_handle_t ***thread_handle_vector, /* OUT */
int *num_handles /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-thread-in-parallel:def}
The \texttt{num\_handles} pointer argument must be valid.
The \texttt{thread\_handle\_vector} pointer argument may be NULL, in which
case the number of handles that would have been returned had the argument
not been NULL is returned in \texttt{*num\_handles}.
The OMPD must obtain the memory for the vector of pointers to thread handles
using the memory allocation callback function that was passed to it
during \refdef{\texttt{ompd\_initialize}}{initialize:def}.
If the OMPD implementation needs to allocate heap memory for the
thread handles it must use the callbacks to acquire this memory.
After the call the vector and the thread handles are `owned' by the debugger,
which is responsible for releasing them.
The thread handles must be released by calling
\refdef{\texttt{ompd\_thread\_handle}}{release-thread-handle:def}.
The vector was allocated by the OMPD implementation using the allocation
routine in the callbacks; the debugger must deallocate the vector
in a compatible manner.
\paragraph{Retrieve the handle for the OpenMP master thread in a parallel
region.}
The \verb|ompd_get_master_thread_in_parallel| operation
enables the debugger to obtain
a handle for the OpenMP master thread in a parallel region.
A successful invocation of \verb|ompd_get_master_thread_in_parallel|
returns a handle
for the thread that encountered the parallel construct. This call yields
meaningful results only if an OpenMP thread in the parallel region is
stopped; otherwise, the parallel region is not guaranteed to be alive.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_master_thread_in_parallel (
ompd_parallel_handle_t *parallel_handle, /* IN */
ompd_thread_handle_t **thread_handle /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-master-thread-in-parallel:def}
On success \texttt{ompd\_get\_master\_thread\_in\_parallel}
returns \texttt{ompd\_rc\_ok}.
A pointer to the thread handle is returned in \texttt{*thread\_handle}.
After the call the thread handle is owned by the debugger,
which must release it when it is no longer required by calling
\refdef{\texttt{ompd\_release\_thread\_handle}}{release-thread-handle:def}.
\paragraph{Release a thread handle.}
Thread handles are opaque to the debugger, which therefore cannot
release them directly.
Instead, when the debugger is finished with a thread handle it
must pass it to the OMPD \texttt{ompd\_release\_thread\_handle}
routine for disposal.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_release_thread_handle (
ompd_thread_handle_t *thread_handle /* IN */
);
\end{lstlisting}
\end{quote}
\labeldef{release-thread-handle:def}
\paragraph{Compare thread handles.}
The internal structure of thread handles is opaque to the debugger.
While the debugger can easily compare pointers to thread handles,
it cannot determine whether handles of two different addresses
refer to the same underlying thread. The following function can be used to
compare thread handles.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_thread_handle_compare (
ompd_thread_handle_t *thread_handle_1, /* IN */
ompd_thread_handle_t *thread_handle_2, /* IN */
int *cmp_value /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{thread-handle-compare:def}
On success, \texttt{ompd\_thread\_handle\_compare} returns in
\texttt{*cmp\_value} a signed integer value that indicates how
the underlying threads compare:
a value less than, equal to, or greater than 0 indicates that
the thread corresponding to \texttt{thread\_handle\_1} is,
respectively, less than, equal to, or greater than that corresponding
to \texttt{thread\_handle\_2}.
\begin{notes}
ilaguna: do we need to give intuition about what we mean by thread1 < thread2
(or vice versa)? Will the OMPD DLL maintain a total order or a partial order of
thread handles? If thread1 < thread2, and thread2 < thread3, is thread1 <
thread3 or can thread1 > thread3?
\end{notes}
For OMPD implementations that always have a single, unique, underlying
thread handle for a given thread, this operation reduces to a simple
comparison of the pointers.
However, other implementations may take a different approach,
and therefore the only reliable way of determining whether two different
pointers to thread handles refer the same or distinct threads is to use
\texttt{ompd\_thread\_handle\_compare}.
Allowing thread handles to be compared allows the debugger to hold
them in ordered collections.
The means by which thread handles are ordered is implementation-defined.
\paragraph{String id.}
The \texttt{ompd\_get\_thread\_handle\_string\_id} function returns a string
that contains a unique printable value that identifies the thread.
The string should be a single sequence of alphanumeric or underscore
characters, and NULL terminated.
\begin{notes}
ilaguna: Why allowing only alphanumeric or underscore characters? As an
implementer I may want to use colon or slash characters for more structured
names.
\end{notes}
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_thread_handle_string_id (
ompd_thread_handle_t *thread_handle, /* IN */
char **string_id /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-thread-handle-string-id:def}
The OMPD implementation allocates the string returned in \texttt{*string\_id}
using the allocation routine in the callbacks passed to it
during initialization.
On return the string is owned by the debugger, which is responsible
for deallocating it.
The contents of the strings returned for thread handles
which compare as equal with
\refdef{\texttt{ompd\_thread\_handle\_compare}}{thread-handle-compare:def}
must be the same.
\subsection{Parallel Region Handles}
\paragraph{Retrieve the handle for the innermost parallel region for an OpenMP
thread.}
The operation \verb|ompd_get_top_parallel_region|
enables the debugger to obtain a pointer to the parallel handle
for the innermost, or topmost,
parallel region associated with an OpenMP thread.
This call is meaningful only if the thread whose handle is provided is stopped.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_top_parallel_region (
ompd_thread_handle_t *thread_handle, /* IN */
ompd_parallel_handle_t **parallel_handle /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-top-parallel-region:def}
The parallel handle must be released by calling
\refdef{\texttt{ompd\_release\_parallel\_handle}}{release-parallel-handle:def}.
\paragraph{Retrieve the handle for an enclosing parallel region.}
The \verb|ompd_get_enclosing_parallel_handle| operation enables
the debugger to obtain a pointer to the parallel handle for the parallel region
enclosing the parallel region specified by \verb|parallel_handle|.
This call is meaningful only if at least one thread in the parallel
region is stopped.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_enclosing_parallel_handle (
ompd_parallel_handle_t *parallel_handle, /* IN */
ompd_parallel_handle_t **enclosing_parallel_handle /* OUT */
);
\end{lstlisting}
\labeldef{get-enclosing-parallel-handle:def}
\end{quote}
On success \texttt{ompd\_get\_enclosing\_parallel\_handle}
returns \texttt{ompd\_rc\_ok}.
A pointer to the parallel handle for the enclosing region is
returned in \texttt{*enclosing\_parallel\_handle}.
After the call the handle is owned by the debugger,
which must release it when it is no longer required by calling
\refdef{\texttt{ompd\_release\_parallel\_handle}}{release-parallel-handle:def}.
\paragraph{Retrieve the handle for the parallel region enclosing a task.}
The \verb|ompd_get_task_parallel_handle| operation enables
the debugger to obtain a pointer to the parallel handle for the parallel region
enclosing the task region specified by \verb|task_handle|.
This call is meaningful only if at least one thread in the parallel
region is stopped.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_task_parallel_handle (
ompd_task_handle_t *task_handle, /* IN */
ompd_parallel_handle_t **task_parallel_handle /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-task-parallel-handle:def}
On success \texttt{ompd\_get\_task\_parallel\_handle}
returns \texttt{ompd\_rc\_ok}.
A pointer to the parallel regions handle
is returned in \texttt{*task\_parallel\_handle}.
The parallel handle is owned by the debugger, which must release it by calling
\refdef{\texttt{ompd\_release\_parallel\_handle}}{release-parallel-handle:def}.
\paragraph{Release a parallel region handle.}
Parallel region handles are opaque to the debugger, which therefore
cannot release them directly.
Instead, when the debugger is finished with a parallel region handle
it must must pass it to the OMPD \texttt{ompd\_release\_parallel\_handle}
routine for disposal.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_release_parallel_handle (
ompd_parallel_handle_t *parallel_handle /* IN */
);
\end{lstlisting}
\end{quote}
\labeldef{release-parallel-handle:def}
\paragraph{Compare parallel region handles.}
The internal structure of parallel region handles is opaque to the debugger.
While the debugger can easily compare pointers to parallel region handles,
it cannot determine whether handles at two different addresses refer to the
same underlying parallel region.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_parallel_handle_compare (
ompd_parallel_handle_t *parallel_handle_1, /* IN */
ompd_parallel_handle_t *parallel_handle_2, /* IN */
int *cmp_value /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{parallel-handle-compare:def}
On success, \texttt{ompd\_parallel\_handle\_compare} returns in
\texttt{*cmp\_value} a signed integer value that indicates how
the underlying parallel regions compare:
a value less than, equal to, or greater than 0 indicates that
the region corresponding to \texttt{parallel\_handle\_1} is,
respectively, less than, equal to, or greater than that corresponding
to \texttt{parallel\_handle\_2}.
For OMPD implementations that always have a single, unique, underlying
parallel region handle for a given parallel region,
this operation reduces to a simple comparison of the pointers.
However, other implementations may take a different approach,
and therefore the only reliable way of determining whether two different
pointers to parallel regions handles refer the same or distinct
parallel regions is to use \texttt{ompd\_parallel\_handle\_compare}.
Allowing parallel region handles to be compared allows the debugger to hold
them in ordered collections.
The means by which parallel region handles are ordered is
implementation-defined.
\paragraph{String id.}
The \texttt{ompd\_get\_parallel\_handle\_string\_id}
function returns a string that contains a unique printable
value that identifies the parallel region.
The string should be a single sequence of alphanumeric or underscore
characters, and NULL terminated.
\begin{notes}
ilaguna: Why allowing only alphanumeric or underscore characters? As an
implementer I may want to use colon or slash characters for more structured
names.
\end{notes}
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_parallel_handle_string_id (
ompd_parallel_handle_t *parallel_handle, /* IN */
char **string_id /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-parallel-handle-string-id:def}
The OMPD implementation allocates the string returned in \texttt{*string\_id}
using the allocation routine in the callbacks passed to it
during initialization.
On return the string is owned by the debugger, which is responsible
for deallocating it.
The contents of the strings returned for parallel regions handles
which compare as equal with
\refdef{\texttt{ompd\_parallel\_handle\_compare}}{parallel-handle-compare:def}
must be the same.
\subsection{Task Handles}
\label{task-handles:sec}
\paragraph{Retrieve the handle for the innermost task for an OpenMP thread.}
The debugger uses the operation \verb|ompd_get_top_task_region|
to obtain a pointer to the task handle for the innermost, or topmost,
task region associated with an OpenMP thread.
This call is meaningful only if the thread whose handle is provided is stopped.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_top_task_region (
ompd_thread_handle_t *thread_handle, /* IN */
ompd_task_handle_t **task_handle /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-top-task-region:def}
The task handle must be released by calling
\refdef{\texttt{ompd\_release\_task\_handle}}{release-task-handle:def}.
\paragraph{Retrieve the handle for an enclosing task.}
The OMPD API includes operations to obtain the handle of the
parent of a task represented by a given task handle.
There are two notions of parenthood.
The \emph{scheduling} parent task is the task that was active
when the child task was scheduled to run.
The \emph{generating} is the task that encountered the OpenMP
that caused the child task to be created.
The generating and scheduling parents need not be the same.
This might happen if the thread executing a task encounters
an OpenMP construct.
When this happens, the thread will enter the runtime.
The runtime will set up the tasks to implement the OpenMP program
construct, and then call its schedular to choose a task to
execute.
If the scheduler chooses a task other than one of these newly
created tasks to run, the scheduling parent of the selected task
will not be the same as its generating parent.
The former is the task that the thread was executing most recently,
and from which it entered the runtime.
The later is the task which encountered the OpenMP construct
it is executing.
The debugger uses \verb|ompd_get_generating_ancestor_task_region| to obtain
a pointer to the task handle for the task that encountered the OpenMP
construct which caused the task represented by \verb|task_handle|
to be created.
This call is meaningful only if the thread executing the task specified by
\verb|task_handle| is stopped.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_generating_ancestor_task_region (
ompd_task_handle_t *task_handle, /* IN */
ompd_task_handle_t **parent_task_handle /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-generating-ancestor-task-region:def}
The \verb|ompd_get_scheduling_ancestor_task_region| returns the
scheduling parent of the task represented \verb|task_handle|.
The scheduling parent task is the OpenMP task that was active when
the child task was scheduled.
This call is meaningful only if the thread executing the task specified by
\verb|task_handle| is stopped.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_scheduling_ancestor_task_region (
ompd_task_handle_t *task_handle, /* IN */
ompd_task_handle_t **parent_task_handle /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-scheduling-ancestor-task-region:def}
The parent task handle must be released by calling
\refdef{\texttt{ompd\_release\_task\_handle}}{release-task-handle:def}.
\paragraph{Retrieve implicit task handle for a parallel region.}
The \verb|ompd_get_implicit_task_in_parallel| operation enables
the debugger to obtain a vector of pointers to task handles for all
implicit tasks associated with a parallel region.
This call is meaningful only if all threads associated
with the parallel region are stopped.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_implicit_task_in_parallel (
ompd_parallel_handle_t *parallel_handle, /* IN */
ompd_task_handle_t ***task_handle_vector, /* OUT */
int *num_handles /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-implicit-task-in-parallel:def}
The OMPD must use the memory allocation callback to obtain the
memory for the vector of pointers to task handles returned by the operation.
If the OMPD implementation needs to allocate heap memory for the
task handles it returns, it must use the callbacks to acquire this memory.
After the call the vector and the task handles are `owned' by the debugger,
which is responsible for deallocating them.
The task handles must be released calling
\refdef{\texttt{ompd\_release\_task\_handle}}{release-task-handle:def}.
The vector was allocated by the OMPD implementation using the
allocation routine passed to it during the call to
\refdef{\texttt{ompd\_initialize}}{initialize:def}.
The debugger itself must deallocate the vector in a compatible manner.
\paragraph{Release a task handle.}
Task handles are opaque to the debugger, which therefore cannot release
them directly.
Instead, when the debugger is finished with a task handle it must
pass it to the OMPD \texttt{ompd\_release\_task\_handle} routine
for disposal.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_release_task_handle (
ompd_task_handle_t *task_handle /* IN */
);
\end{lstlisting}
\end{quote}
\labeldef{release-task-handle:def}
\paragraph{Compare task handles.}
The internal structure of task handles is opaque to the debugger.
While the debugger can easily compare pointers to task handles,
it cannot determine whether handles at two different addresses refer
to the same underlying task.
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_task_handle_compare (
ompd_task_handle_t *task_handle_1, /* IN */
ompd_task_handle_t *task_handle_2, /* IN */
int *cmp_value /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{task-handle-compare:def}
On success, \texttt{ompd\_task\_handle\_compare} returns in
\texttt{*cmp\_value} a signed integer value that indicates how
the underlying tasks compare:
a value less than, equal to, or greater than 0 indicates that
the task corresponding to \texttt{task\_handle\_1} is,
respectively, less than, equal to, or greater than that corresponding
to \texttt{task\_handle\_2}.
For OMPD implementations that always have a single, unique, underlying
task handle for a given task,
this operation reduces to a simple comparison of the pointers.
However, other implementations may take a different approach,
and therefore the only reliable way of determining whether two different
pointers to task handles refer the same or distinct
task is to use \texttt{ompd\_task\_handle\_compare}.
Allowing task handles to be compared allows the debugger to hold
them in ordered collections.
The means by which task handles are ordered is implementation-defined.
\paragraph{String id.}
The \texttt{ompd\_get\_task\_handle\_string\_id}
function returns a string that contains a unique printable
value that identifies the task.
The string should be a single sequence of alphanumeric or underscore
characters, and NULL terminated.
\begin{notes}
ilaguna: Why allowing only alphanumeric or underscore characters? As an
implementer I may want to use colon or slash characters for more structured
names.
\end{notes}
\begin{quote}
\begin{lstlisting}
ompd_rc_t ompd_get_task_handle_string_id (
ompd_task_handle_t *task_handle, /* IN */
char **string_id /* OUT */
);
\end{lstlisting}
\end{quote}
\labeldef{get-task-handle-string-id:def}
The OMPD implementation allocates the string returned in \texttt{*string\_id}
using the allocation routine in the callbacks passed to it
during initialization.
On return the string is owned by the debugger, which is responsible
for deallocating it.
The contents of the strings returned for task handles
which compare as equal with
\refdef{\texttt{ompd\_task\_handle\_compare}}{task-handle-compare:def}
must be the same.