2 // Copyright (C) 2005-2011 Red Hat Inc.
3 // Copyright (C) 2005-2007 Intel Corporation.
5 // This file is part of systemtap, and is free software. You can
6 // redistribute it and/or modify it under the terms of the GNU General
7 // Public License (GPL); either version 2, or (at your option) any
13 #include "translate.h"
21 using namespace __gnu_cxx
;
24 static const string
TOK_TIMER("timer");
27 // ------------------------------------------------------------------------
28 // timer derived probes
29 // ------------------------------------------------------------------------
32 struct timer_derived_probe
: public derived_probe
34 int64_t interval
, randomize
;
35 bool time_is_msecs
; // NB: hrtimers get ms-based probes on modern kernels instead
36 timer_derived_probe (probe
* p
, probe_point
* l
,
37 int64_t i
, int64_t r
, bool ms
=false);
38 virtual void join_group (systemtap_session
& s
);
40 // No assertion need be emitted, since this probe is allowed for unprivileged
42 void emit_privilege_assertion (translator_output
*) {}
43 void print_dupe_stamp(ostream
& o
) { print_dupe_stamp_unprivileged (o
); }
47 struct timer_derived_probe_group
: public generic_dpg
<timer_derived_probe
>
49 void emit_interval (translator_output
* o
);
51 void emit_module_decls (systemtap_session
& s
);
52 void emit_module_init (systemtap_session
& s
);
53 void emit_module_exit (systemtap_session
& s
);
57 timer_derived_probe::timer_derived_probe (probe
* p
, probe_point
* l
,
58 int64_t i
, int64_t r
, bool ms
):
59 derived_probe (p
, l
), interval (i
), randomize (r
), time_is_msecs(ms
)
61 if (interval
<= 0 || interval
> 1000000) // make i and r fit into plain ints
62 //TRANSLATORS: 'timer' is the name of a probe point
63 throw SEMANTIC_ERROR (_("invalid interval for jiffies timer"));
64 // randomize = 0 means no randomization
65 if (randomize
< 0 || randomize
> interval
)
66 //TRANSLATORS: 'randomize' is a key word
67 throw SEMANTIC_ERROR (_("invalid randomize for jiffies timer"));
69 if (locations
.size() != 1)
70 throw SEMANTIC_ERROR (_("only expect one probe point"));
71 // so we don't have to loop over them in the other functions
76 timer_derived_probe::join_group (systemtap_session
& s
)
78 if (! s
.timer_derived_probes
)
79 s
.timer_derived_probes
= new timer_derived_probe_group ();
80 s
.timer_derived_probes
->enroll (this);
85 timer_derived_probe_group::emit_interval (translator_output
* o
)
88 o
->newline(1) << "unsigned i = stp->intrv;";
89 o
->newline() << "if (stp->rnd != 0)";
90 o
->newline(1) << "i += _stp_random_pm(stp->rnd);";
91 o
->newline(-1) << "stp->ms ? msecs_to_jiffies(i) : i;";
92 o
->newline(-1) << "})";
97 timer_derived_probe_group::emit_module_decls (systemtap_session
& s
)
99 if (probes
.empty()) return;
101 s
.op
->newline() << "/* ---- timer probes ---- */";
103 s
.op
->newline() << "static struct stap_timer_probe {";
104 s
.op
->newline(1) << "struct timer_list timer_list;";
105 s
.op
->newline() << "const struct stap_probe * const probe;";
106 s
.op
->newline() << "unsigned intrv, ms, rnd;";
107 s
.op
->newline(-1) << "} stap_timer_probes [" << probes
.size() << "] = {";
109 for (unsigned i
=0; i
< probes
.size(); i
++)
111 s
.op
->newline () << "{";
112 s
.op
->line() << " .probe=" << common_probe_init (probes
[i
]) << ",";
113 s
.op
->line() << " .intrv=" << probes
[i
]->interval
<< ",";
114 s
.op
->line() << " .ms=" << probes
[i
]->time_is_msecs
<< ",";
115 s
.op
->line() << " .rnd=" << probes
[i
]->randomize
;
116 s
.op
->line() << " },";
118 s
.op
->newline(-1) << "};";
121 s
.op
->newline() << "static void enter_timer_probe (unsigned long val) {";
122 s
.op
->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [val];";
123 s
.op
->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
124 s
.op
->newline() << " (atomic_read (session_state()) == STAP_SESSION_RUNNING))";
125 s
.op
->newline(1) << "mod_timer (& stp->timer_list, jiffies + ";
126 emit_interval (s
.op
);
127 s
.op
->line() << ");";
128 s
.op
->newline(-1) << "{";
130 common_probe_entryfn_prologue (s
, "STAP_SESSION_RUNNING", "stp->probe",
131 "stp_probe_type_timer");
132 s
.op
->newline() << "(*stp->probe->ph) (c);";
133 common_probe_entryfn_epilogue (s
, true);
134 s
.op
->newline(-1) << "}";
135 s
.op
->newline(-1) << "}";
140 timer_derived_probe_group::emit_module_init (systemtap_session
& s
)
142 if (probes
.empty()) return;
144 s
.op
->newline() << "for (i=0; i<" << probes
.size() << "; i++) {";
145 s
.op
->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [i];";
146 s
.op
->newline() << "probe_point = stp->probe->pp;";
147 s
.op
->newline() << "init_timer (& stp->timer_list);";
148 s
.op
->newline() << "stp->timer_list.function = & enter_timer_probe;";
149 s
.op
->newline() << "stp->timer_list.data = i;"; // NB: important!
150 // copy timer renew calculations from above :-(
151 s
.op
->newline() << "stp->timer_list.expires = jiffies + ";
152 emit_interval (s
.op
);
154 s
.op
->newline() << "add_timer (& stp->timer_list);";
155 // note: no partial failure rollback is needed: add_timer cannot fail.
156 s
.op
->newline(-1) << "}"; // for loop
161 timer_derived_probe_group::emit_module_exit (systemtap_session
& s
)
163 if (probes
.empty()) return;
165 s
.op
->newline() << "for (i=0; i<" << probes
.size() << "; i++)";
166 s
.op
->newline(1) << "del_timer_sync (& stap_timer_probes[i].timer_list);";
172 // ------------------------------------------------------------------------
173 // hrtimer derived probes
174 // ------------------------------------------------------------------------
175 // This is a new timer interface that provides more flexibility in specifying
176 // intervals, and uses the hrtimer APIs when available for greater precision.
177 // While hrtimers were added in 2.6.16, the API's weren't exported until
178 // 2.6.17, so we must check this kernel version before attempting to use
181 // * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs.
184 struct hrtimer_derived_probe
: public derived_probe
186 // set a (generous) maximum of one day in ns
187 static const int64_t max_ns_interval
= 1000000000LL * 60LL * 60LL * 24LL;
189 // 100us seems like a reasonable minimum
190 static const int64_t min_ns_interval
= 100000LL;
192 int64_t interval
, randomize
;
194 hrtimer_derived_probe (probe
* p
, probe_point
* l
, int64_t i
, int64_t r
,
196 derived_probe (p
, l
), interval (i
), randomize (r
)
198 if ((i
< min_ns_interval
) || (i
> max_ns_interval
))
199 throw SEMANTIC_ERROR(_F("interval value out of range (%s, %s)",
200 (lex_cast(scale
< min_ns_interval
? min_ns_interval
/scale
: 1).c_str()),
201 lex_cast(max_ns_interval
/scale
).c_str()));
203 // randomize = 0 means no randomization
204 if ((r
< 0) || (r
> i
))
205 throw SEMANTIC_ERROR(_("randomization value out of range"));
208 void join_group (systemtap_session
& s
);
210 // No assertion need be emitted, since these probes are allowed for
211 // unprivileged users.
212 void emit_privilege_assertion (translator_output
*) {}
213 void print_dupe_stamp(ostream
& o
) { print_dupe_stamp_unprivileged (o
); }
217 struct hrtimer_derived_probe_group
: public generic_dpg
<hrtimer_derived_probe
>
220 void emit_module_decls (systemtap_session
& s
);
221 void emit_module_init (systemtap_session
& s
);
222 void emit_module_exit (systemtap_session
& s
);
227 hrtimer_derived_probe::join_group (systemtap_session
& s
)
229 if (! s
.hrtimer_derived_probes
)
230 s
.hrtimer_derived_probes
= new hrtimer_derived_probe_group ();
231 s
.hrtimer_derived_probes
->enroll (this);
236 hrtimer_derived_probe_group::emit_module_decls (systemtap_session
& s
)
238 if (probes
.empty()) return;
240 s
.op
->newline() << "/* ---- hrtimer probes ---- */";
241 s
.op
->newline() << "#include \"timer.c\"";
242 s
.op
->newline() << "static struct stap_hrtimer_probe stap_hrtimer_probes [" << probes
.size() << "] = {";
245 for (unsigned i
=0; i
< probes
.size(); i
++)
247 s
.op
->newline () << "{";
248 s
.op
->line() << " .probe=" << common_probe_init (probes
[i
]) << ",";
249 s
.op
->line() << " .intrv=" << probes
[i
]->interval
<< "LL,";
250 s
.op
->line() << " .rnd=" << probes
[i
]->randomize
<< "LL";
251 s
.op
->line() << " },";
253 s
.op
->newline(-1) << "};";
256 if (!s
.runtime_usermode_p())
258 s
.op
->newline() << "static hrtimer_return_t _stp_hrtimer_notify_function (struct hrtimer *timer) {";
260 s
.op
->newline(1) << "int rc = HRTIMER_NORESTART;";
261 s
.op
->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);";
263 // Update the timer with the next trigger time
264 s
.op
->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
265 s
.op
->newline() << " (atomic_read (session_state()) == STAP_SESSION_RUNNING)) {";
266 s
.op
->newline(1) << "_stp_hrtimer_update(stp);";
267 s
.op
->newline() << "rc = HRTIMER_RESTART;";
268 s
.op
->newline(-1) << "}";
270 s
.op
->newline() << "{";
272 common_probe_entryfn_prologue (s
, "STAP_SESSION_RUNNING", "stp->probe",
273 "stp_probe_type_hrtimer");
274 s
.op
->newline() << "(*stp->probe->ph) (c);";
275 common_probe_entryfn_epilogue (s
, true);
276 s
.op
->newline(-1) << "}";
277 s
.op
->newline() << "return rc;";
278 s
.op
->newline(-1) << "}";
282 s
.op
->newline() << "static void _stp_hrtimer_notify_function (sigval_t value)";
283 s
.op
->newline(1) << "{";
284 s
.op
->newline() << "struct stap_hrtimer_probe *stp = value.sival_ptr;";
286 // Update the timer with the next trigger time
287 s
.op
->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
288 s
.op
->newline() << " (atomic_read (session_state()) == STAP_SESSION_RUNNING)) {";
289 s
.op
->newline(1) << "_stp_hrtimer_update(stp);";
290 s
.op
->newline(-1) << "}";
292 s
.op
->newline() << "{";
294 common_probe_entryfn_prologue (s
, "STAP_SESSION_RUNNING", "stp->probe",
295 "stp_probe_type_hrtimer");
296 s
.op
->newline() << "(*stp->probe->ph) (c);";
297 common_probe_entryfn_epilogue (s
, true);
298 s
.op
->newline(-1) << "}";
299 s
.op
->newline(-1) << "}";
305 hrtimer_derived_probe_group::emit_module_init (systemtap_session
& s
)
307 if (probes
.empty()) return;
309 s
.op
->newline() << "_stp_hrtimer_init();";
310 s
.op
->newline() << "for (i=0; i<" << probes
.size() << "; i++) {";
311 s
.op
->newline(1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
312 s
.op
->newline() << "probe_point = stp->probe->pp;";
314 // Note: no partial failure rollback is needed for kernel hrtimer
315 // probes (hrtimer_start only "fails" if the timer was already
316 // active, which cannot be). But, stapdyn timer probes need a
317 // rollback, and it won't hurt the kernel hrtimers.
318 s
.op
->newline() << "rc = _stp_hrtimer_create(stp, _stp_hrtimer_notify_function);";
319 s
.op
->newline() << "if (rc) {";
321 s
.op
->newline() << "for (j=i-1; j>=0; j--)"; // partial rollback
322 s
.op
->newline(1) << "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
323 s
.op
->newline(-1) << "break;"; // don't attempt to register any more
324 s
.op
->newline(-1) << "}";
325 s
.op
->newline(-1) << "}"; // for loop
330 hrtimer_derived_probe_group::emit_module_exit (systemtap_session
& s
)
332 if (probes
.empty()) return;
334 s
.op
->newline() << "for (i=0; i<" << probes
.size() << "; i++)";
336 s
.op
->newline() << "_stp_hrtimer_cancel(& stap_hrtimer_probes[i]);";
342 // ------------------------------------------------------------------------
343 // profile derived probes
344 // ------------------------------------------------------------------------
345 // On kernels < 2.6.10, this uses the register_profile_notifier API to
346 // generate the timed events for profiling; on kernels >= 2.6.10 this
347 // uses the register_timer_hook API. The latter doesn't currently allow
348 // simultaneous users, so insertion will fail if the profiler is busy.
349 // (Conflicting users may include OProfile, other SystemTap probes, etc.)
352 struct profile_derived_probe
: public derived_probe
354 profile_derived_probe (systemtap_session
&s
, probe
* p
, probe_point
* l
);
355 void join_group (systemtap_session
& s
);
359 struct profile_derived_probe_group
: public generic_dpg
<profile_derived_probe
>
362 void emit_module_decls (systemtap_session
& s
);
363 void emit_module_init (systemtap_session
& s
);
364 void emit_module_exit (systemtap_session
& s
);
368 profile_derived_probe::profile_derived_probe (systemtap_session
&, probe
* p
, probe_point
* l
):
375 profile_derived_probe::join_group (systemtap_session
& s
)
377 if (! s
.profile_derived_probes
)
378 s
.profile_derived_probes
= new profile_derived_probe_group ();
379 s
.profile_derived_probes
->enroll (this);
383 // timer.profile probe handlers are hooked up in an entertaining way
384 // to the underlying kernel facility. The fact that 2.6.11+ era
385 // "register_timer_hook" API allows only one consumer *system-wide*
386 // will give a hint. We will have a single entry function (and thus
387 // trivial registration / unregistration), and it will call all probe
388 // handler functions in sequence.
391 profile_derived_probe_group::emit_module_decls (systemtap_session
& s
)
393 if (probes
.empty()) return;
395 // kernels < 2.6.10: use register_profile_notifier API
396 // kernels >= 2.6.10: use register_timer_hook API
397 s
.op
->newline() << "/* ---- profile probes ---- */";
399 // This function calls all the profiling probe handlers in sequence.
400 // The only tricky thing is that the context will be reused amongst
401 // them. While a simple sequence of calls to the individual probe
402 // handlers is unlikely to go terribly wrong (with c->last_error
403 // being set causing an early return), but for extra assurance, we
404 // open-code the same logic here.
406 s
.op
->newline() << "static void enter_all_profile_probes (struct pt_regs *regs) {";
407 s
.op
->newline(1) << "const struct stap_probe * probe = "
408 << common_probe_init (probes
[0]) << ";";
409 common_probe_entryfn_prologue (s
, "STAP_SESSION_RUNNING", "probe",
410 "stp_probe_type_profile_timer");
411 // Timer interrupts save all registers, so if the interrupt happened
412 // in user space we can rely on it being the full user pt_regs.
413 s
.op
->newline() << "if (user_mode(regs)) {";
414 s
.op
->newline(1) << "c->user_mode_p = 1;";
415 s
.op
->newline() << "c->uregs = regs;";
416 s
.op
->newline(-1) << "} else {";
417 s
.op
->newline(1) << "c->kregs = regs;";
418 s
.op
->newline(-1) << "}";
420 for (unsigned i
=0; i
<probes
.size(); i
++)
424 // Some lightweight inter-probe context resetting
425 // XXX: not quite right: MAXERRORS not respected
426 // XXX: STP_TIMING stats are also not correct
427 s
.op
->newline() << "probe = " << common_probe_init (probes
[i
]) << ";";
428 s
.op
->newline() << "#ifdef STP_NEED_PROBE_NAME";
429 s
.op
->newline() << "c->probe_name = probe->pn;";
430 s
.op
->newline() << "#endif";
431 if(!s
.suppress_time_limits
)
433 s
.op
->newline() << "c->actionremaining = MAXACTION;";
436 s
.op
->newline() << "if (c->last_error == NULL) probe->ph (c);";
438 common_probe_entryfn_epilogue (s
, true);
439 s
.op
->newline(-1) << "}";
441 s
.op
->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
443 s
.op
->newline() << "static int enter_profile_probes (struct notifier_block *self,"
444 << " unsigned long val, void *data) {";
445 s
.op
->newline(1) << "(void) self; (void) val;";
446 s
.op
->newline() << "enter_all_profile_probes ((struct pt_regs *) data);";
447 s
.op
->newline() << "return 0;";
448 s
.op
->newline(-1) << "}";
449 s
.op
->newline() << "struct notifier_block stap_profile_notifier = {"
450 << " .notifier_call = & enter_profile_probes };";
452 s
.op
->newline() << "#else";
454 s
.op
->newline() << "static int enter_profile_probes (struct pt_regs *regs) {";
455 s
.op
->newline(1) << "enter_all_profile_probes (regs);";
456 s
.op
->newline() << "return 0;";
457 s
.op
->newline(-1) << "}";
459 s
.op
->newline() << "#endif";
464 profile_derived_probe_group::emit_module_init (systemtap_session
& s
)
466 if (probes
.empty()) return;
468 s
.op
->newline() << "probe_point = \"timer.profile\";"; // NB: hard-coded for convenience
469 s
.op
->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
470 s
.op
->newline() << "rc = register_profile_notifier (& stap_profile_notifier);";
471 s
.op
->newline() << "#else";
472 s
.op
->newline() << "rc = register_timer_hook (& enter_profile_probes);";
473 s
.op
->newline() << "#endif";
478 profile_derived_probe_group::emit_module_exit (systemtap_session
& s
)
480 if (probes
.empty()) return;
482 s
.op
->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
483 s
.op
->newline() << "unregister_profile_notifier (& stap_profile_notifier);";
484 s
.op
->newline() << "#else";
485 s
.op
->newline() << "unregister_timer_hook (& enter_profile_probes);";
486 s
.op
->newline() << "#endif";
491 // ------------------------------------------------------------------------
492 // unified probe builder for timer probes
493 // ------------------------------------------------------------------------
496 struct timer_builder
: public derived_probe_builder
498 virtual void build(systemtap_session
& sess
,
499 probe
* base
, probe_point
* location
,
500 literal_map_t
const & parameters
,
501 vector
<derived_probe
*> & finished_results
);
503 static void register_patterns(systemtap_session
& s
);
507 timer_builder::build(systemtap_session
& sess
,
509 probe_point
* location
,
510 literal_map_t
const & parameters
,
511 vector
<derived_probe
*> & finished_results
)
513 int64_t scale
=1, period
, rand
=0;
515 if (has_null_param(parameters
, "profile"))
517 if (sess
.runtime_usermode_p())
518 throw SEMANTIC_ERROR (_("profile timer probes not available with the dyninst runtime"));
520 /* As the latest mechanism for timer hook support has been
521 removed, we need to bail explicitly if the corresponding
522 symbols are missing: */
523 if ((sess
.kernel_exports
.find("register_timer_hook") == sess
.kernel_exports
.end()
524 || sess
.kernel_exports
.find("unregister_timer_hook") == sess
.kernel_exports
.end())
525 && (sess
.kernel_exports
.find("register_profile_notifier") == sess
.kernel_exports
.end()
526 || sess
.kernel_exports
.find("unregister_profile_notifier") == sess
.kernel_exports
.end()))
527 throw SEMANTIC_ERROR (_("profiling timer support (register_timer_hook) not found in kernel!"));
529 sess
.unwindsym_modules
.insert ("kernel");
530 finished_results
.push_back
531 (new profile_derived_probe(sess
, base
, location
));
535 if (!get_param(parameters
, "randomize", rand
))
538 if (get_param(parameters
, "jiffies", period
))
540 if (sess
.runtime_usermode_p())
541 throw SEMANTIC_ERROR (_("jiffies timer probes not available with the dyninst runtime"));
543 // always use basic timers for jiffies
544 finished_results
.push_back
545 (new timer_derived_probe(base
, location
, period
, rand
, false));
548 else if (get_param(parameters
, "hz", period
))
551 throw SEMANTIC_ERROR (_("frequency must be greater than 0"));
552 period
= (1000000000 + period
- 1)/period
;
554 else if (get_param(parameters
, "s", period
) ||
555 get_param(parameters
, "sec", period
))
561 else if (get_param(parameters
, "ms", period
) ||
562 get_param(parameters
, "msec", period
))
568 else if (get_param(parameters
, "us", period
) ||
569 get_param(parameters
, "usec", period
))
575 else if (get_param(parameters
, "ns", period
) ||
576 get_param(parameters
, "nsec", period
))
581 throw SEMANTIC_ERROR (_("unrecognized timer variant"));
583 // Redirect wallclock-time based probes to hrtimer code on recent
585 if (strverscmp(sess
.kernel_base_release
.c_str(), "2.6.17") < 0)
587 // hrtimers didn't exist, so use the old-school timers
588 period
= (period
+ 1000000 - 1)/1000000;
589 rand
= (rand
+ 1000000 - 1)/1000000;
591 finished_results
.push_back
592 (new timer_derived_probe(base
, location
, period
, rand
, true));
595 finished_results
.push_back
596 (new hrtimer_derived_probe(base
, location
, period
, rand
, scale
));
600 register_tapset_timers(systemtap_session
& s
)
602 match_node
* root
= s
.pattern_root
;
603 derived_probe_builder
*builder
= new timer_builder();
605 root
= root
->bind(TOK_TIMER
);
608 ->bind_privilege(pr_all
)
610 root
->bind_num("s")->bind_num("randomize")
611 ->bind_privilege(pr_all
)
613 root
->bind_num("sec")
614 ->bind_privilege(pr_all
)
616 root
->bind_num("sec")->bind_num("randomize")
617 ->bind_privilege(pr_all
)
621 ->bind_privilege(pr_all
)
623 root
->bind_num("ms")->bind_num("randomize")
624 ->bind_privilege(pr_all
)
626 root
->bind_num("msec")
627 ->bind_privilege(pr_all
)
629 root
->bind_num("msec")->bind_num("randomize")
630 ->bind_privilege(pr_all
)
634 ->bind_privilege(pr_all
)
636 root
->bind_num("us")->bind_num("randomize")
637 ->bind_privilege(pr_all
)
639 root
->bind_num("usec")
640 ->bind_privilege(pr_all
)
642 root
->bind_num("usec")->bind_num("randomize")
643 ->bind_privilege(pr_all
)
647 ->bind_privilege(pr_all
)
649 root
->bind_num("ns")->bind_num("randomize")
650 ->bind_privilege(pr_all
)
652 root
->bind_num("nsec")
653 ->bind_privilege(pr_all
)
655 root
->bind_num("nsec")->bind_num("randomize")
656 ->bind_privilege(pr_all
)
659 root
->bind_num("jiffies")
660 ->bind_privilege(pr_all
)
662 root
->bind_num("jiffies")->bind_num("randomize")
663 ->bind_privilege(pr_all
)
667 ->bind_privilege(pr_all
)
670 // Not ok for unprivileged users, because register_timer_hook only
671 // allows a single attached callback. No resource-sharing -> no
672 // unprivileged access.
674 // Sigh, but for dyninst users, we want a semantic error that
675 // profile probes aren't supported (which will come from
676 // timer_builder::build()), not a privilege error. So, we'll fake
677 // it so that profile probes are allowed for all.
678 if (!s
.runtime_usermode_p()) {
679 root
->bind("profile")
684 root
->bind("profile")
686 ->bind_privilege(pr_all
)
693 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */