-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathnetsys_posix.mli
1438 lines (1134 loc) · 53.1 KB
/
netsys_posix.mli
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
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* $Id$ *)
(** POSIX-specific system calls missing in the [Unix] module, and
further API's from POSIX-style operating systems.
*)
(** {1 Files, Processes, TTYs, Users, Groups} *)
val int_of_file_descr : Unix.file_descr -> int
(** Return the file descriptor as integer. See also
{!Netsys.int64_of_file_descr} which works for all OS.
*)
val file_descr_of_int : int -> Unix.file_descr
(** Make a file descriptor from an integer *)
external sysconf_open_max : unit -> int = "netsys_sysconf_open_max"
(** Return the maximum number of open file descriptor per process.
* It is also ensured that for every file descriptor [fd]:
* [fd < sysconf_open_max()]
*)
external get_nonblock : Unix.file_descr -> bool = "netsys_get_nonblock"
(** Returns whether the nonblock flag is set *)
external fchdir : Unix.file_descr -> unit = "netsys_fchdir"
(** Set the current directory to the directory referenced by the
file descriptor
*)
external fdopendir : Unix.file_descr -> Unix.dir_handle = "netsys_fdopendir"
(** Make a directory handle from a file descriptor. The descriptor
is then "owned" by the directory handle, and will be closed by
[Unix.closedir].
This function is useful in conjunction with {!Netsys_posix.openat}
to read directories relative to a parent directory.
This is a recent addition to the POSIX standard; be prepared to
get [Invalid_argument] because it is unavailable.
*)
external realpath : string -> string = "netsys_realpath"
(** Returns a pathname pointing to the same filesystem object so that
the pathname does not include "." or ".." or symbolic links.
*)
(* Process groups, sessions, terminals *)
external getpgid : int -> int = "netsys_getpgid"
(** Return the process group ID of the process with the passed PID.
* For the number 0, the process group ID of the current process is
* returned.
*)
val getpgrp : unit -> int
(** Same as [getpgid 0], i.e. returns the process group ID of the
* current process.
*)
external setpgid : int -> int -> unit = "netsys_setpgid"
(** [setpgid pid pgid]: Set the process group ID of the process [pid]
* to [pgid]. If [pid = 0], the process group ID of the current process
* is changed. If [pgid = 0], as process group ID the process ID of the
* process referenced by [pid] is used.
*
* It is only possible for a process to join a process group if both
* belong to the same session.
*)
val setpgrp : unit -> unit
(** Same as [setpgid 0 0]: A new process group ID is created, and the
* current process becomes its sole member.
*)
external tcgetpgrp : Unix.file_descr -> int = "netsys_tcgetpgrp"
(** Return the process group ID of the foreground process group of
* the session associated with the file descriptor, which must be
* a tty.
*)
external tcsetpgrp : Unix.file_descr -> int -> unit = "netsys_tcsetpgrp"
(** Sets the foreground process group ID of the session associated
* with the file descriptor, which must be a tty.
*)
external ctermid : unit -> string = "netsys_ctermid"
(** Returns the name of the controlling tty of the current process
* as pathname to a device file
*)
external ttyname : Unix.file_descr -> string = "netsys_ttyname"
(** Returns the name of the controlling tty referred to by the
* file descriptor.
*)
external getsid : int -> int = "netsys_getsid"
(** Returns the session ID of the process with the passed PID.
* For the PID 0, the session ID of the current process is returned.
*)
val with_tty : (Unix.file_descr -> unit) -> unit
(** [with_tty f]: Runs [f fd] where [fd] is the terminal of the process.
If the process does not have a terminal (because it is a daemon)
[with_tty] will fail.
*)
val tty_read_password : ?tty:Unix.file_descr -> string -> string
(** [tty_read_password prompt]: If [tty] is a terminal, the [prompt]
is printed, and a password is read from the terminal (echo off).
If [tty] is not a terminal, no [prompt] is printed, and just a
line is read from the [tty] descriptor (non-interactive case).
[tty] defaults to [Unix.stdin]. If this function is used in a
program where stdin is not redirected, and the program is started
in a terminal, it will read the password with prompt and
echo disabled. If stdin is redirected, it is assumed that the program is
used in a script, and the password is piped into it.
Use in conjunction with [with_tty] to ensure that [tty] is
the terminal even if a redirection is in effect, e.g.
{[ with_tty (fun tty -> tty_read_password ~tty prompt) ]}
Raises [Sys.Break] if the user triggers SIGINT (i.e. presses
CTRL-C) to abort the input of a password.
*)
external posix_openpt : bool -> Unix.file_descr = "netsys_posix_openpt"
(** [posix_openpt noctty]: Opens an unused PTY master.
[noctty]: If true, the descriptor will not become the controlling
terminal.
If this function is not provided by the OS, an emulation is used.
On some OS, System V style PTY's are unavailable (but they get
rare).
*)
external grantpt : Unix.file_descr -> unit = "netsys_grantpt"
(** Grant access to this PTY *)
external unlockpt : Unix.file_descr -> unit = "netsys_unlockpt"
(** Unlock a PTY master/slave pair *)
external ptsname : Unix.file_descr -> string = "netsys_ptsname"
(** Get the name of the slave PTY *)
type node_type =
| S_IFREG
| S_IFCHR of int (* major + minor *)
| S_IFBLK of int (* major + minor *)
| S_IFIFO
| S_IFSOCK
external mknod : string -> int -> node_type -> unit = "netsys_mknod"
(** Creates the node with the given permissions and the given type *)
(* Users and groups *)
external setreuid : int -> int -> unit = "netsys_setreuid"
(** Changes both the real and the effective user ID of the current
* process.
*)
external setregid : int -> int -> unit = "netsys_setregid"
(** Changes both the real and the effective group ID of the current
* process.
*)
external initgroups : string -> int -> unit = "netsys_initgroups"
(** See initgroups(3). This is a non-POSIX function but widely
available.
*)
(** {1 The "at" variants of system calls} *)
(** Note that a few "at" calls have been omitted because the same
functionality can be achieved by first opening the file with
[openat] and then by using a function that references the file
by descriptor. An example for this is [fstatat]: After the
[openat] call one can use [fstat] to get the stat record of the
file.
*)
val have_at : unit -> bool
(** Whether the [*at] functions are available (they were only recently
standardized and cannot be expected on all OS yet)
*)
val at_fdcwd : Unix.file_descr
(** Pseudo descriptor value to be used as first argument of [*at]
functions
*)
type at_flag = AT_EACCESS | AT_SYMLINK_NOFOLLOW | AT_SYMLINK_FOLLOW |
AT_REMOVEDIR
(** Flags one can pass to "at" functions. Not all functions support
all flags
*)
val openat : Unix.file_descr -> string -> Unix.open_flag list ->
Unix.file_perm ->
Unix.file_descr
(** Same as [Unix.openfile] but open relative to the directory given
by first argument
*)
val faccessat : Unix.file_descr -> string -> Unix.access_permission list ->
at_flag list ->
unit
(** Same as [Unix.access] but the file is taken relative to the directory
given by first argument
*)
val mkdirat : Unix.file_descr -> string -> int -> unit
(** Same as [Unix.mkdir] but the file is taken relative to the directory
given by first argument
*)
val renameat : Unix.file_descr -> string -> Unix.file_descr -> string -> unit
(** [renameat olddirfd oldpath newdirfd newpath] *)
val linkat : Unix.file_descr -> string -> Unix.file_descr -> string ->
at_flag list -> unit
(** [linkat olddirfd oldpath newdirfd newpath flags] *)
val unlinkat : Unix.file_descr -> string -> at_flag list -> unit
(** Same as [Unix.unlink] but unlink the file relative to the directory
given by first argument
*)
val symlinkat : string -> Unix.file_descr -> string -> unit
(** [symlinkat oldpath newdirfd newpath flags] *)
val mkfifoat : Unix.file_descr -> string -> int -> unit
(** [mkfifoat dirfd path mode]
NB. MacOS 10.10 doesn't support mkfifoat although the other "at" functions
are implemented. Be prepared to get [Invalid_argument].
*)
val readlinkat : Unix.file_descr -> string -> string
(** [readlinkat dirfd path] *)
(* TODO: futimens *)
(** {1 File descriptor polling} *)
type poll_array
(** The array of [poll_cell] entries *)
type poll_req_events
type poll_act_events
(** Poll events. [poll_req_events] is used to request that certain
event types are observed. [poll_act_event] shows which
event types are actually possible
*)
type poll_cell =
{ mutable poll_fd : Unix.file_descr;
mutable poll_req_events : poll_req_events;
mutable poll_act_events : poll_act_events;
}
(** The poll cell refers to the descriptor [poll_fd]. The [poll_req_events]
are the events the descriptor is polled for. The [poll_act_events]
are the actually reported events.
*)
val have_poll : unit -> bool
(** Whether there is a native [poll] implementation on this OS *)
val poll_req_events : bool -> bool -> bool -> poll_req_events
(** [poll_req_events rd wr pri]: Create a set of in events consisting
of the bits [rd], [wr], and [pri]. [rd] means to poll for
input data, [wr] to poll for output data, and [pri] to poll for urgent
input data.
*)
val poll_req_triple : poll_req_events -> bool * bool * bool
(** Looks into a [poll_req_events] value, and returns the triple
[(rd,wr,pri)].
*)
val poll_null_events : unit -> poll_act_events
(** Create an empty set of [poll_act_events], for initilization
of poll cells.
*)
val poll_result : poll_act_events -> bool
(** Look whether there is any event in [poll_out_events] *)
val poll_rd_result : poll_act_events -> bool
val poll_wr_result : poll_act_events -> bool
val poll_pri_result : poll_act_events -> bool
val poll_err_result : poll_act_events -> bool
val poll_hup_result : poll_act_events -> bool
val poll_nval_result : poll_act_events -> bool
(** Look for the bit in [poll_act_events] and return the status *)
val create_poll_array : int -> poll_array
(** Create a poll array with the given size. The [poll_fd] member is
initialized with [Unix.stdin], and the two event members are empty.
*)
val set_poll_cell : poll_array -> int -> poll_cell -> unit
(** [set_poll_cell a k c]: Sets the poll cell [k] to [c].
The index [k] must be in the range from [0] to [N-1] when [N] is the
length of the poll array.
*)
val get_poll_cell : poll_array -> int -> poll_cell
(** [get_poll_cell a k]: Returns the poll cell [k].
The index [k] must be in the range from [0] to [N-1] when [N] is the
length of the poll array.
*)
val blit_poll_array : poll_array -> int -> poll_array -> int -> int -> unit
(** [blit_poll_array a1 p1 a2 p2 len]: Copies the [len] cells at index [p1]
from [a1] to [a2] at index [p2].
*)
val poll_array_length : poll_array -> int
(** Return the number of cells in the poll array *)
val poll : poll_array -> int -> float -> int
(** [poll a n tmo]: Poll for the events of the cells 0 to [n-1] of
poll array [a], and set the [poll_act_events] member of all cells.
Wait for at most [tmo] seconds (a negative value means there is
no timeout). Returns the number of ready file descriptors.
On platforms without native support for [poll] the function is
emulated using [Unix.select]. Note, however, that there is a
performance penalty for the emulation, and that the output
flags [poll_error_result], [poll_hangup_result], and
[poll_invalid_result] are not emulated.
*)
val restarting_poll :
poll_array -> int -> float -> int
(** A wrapper around [poll] that handles the [EINTR] condition *)
val poll_single : Unix.file_descr -> bool -> bool -> bool -> float -> bool
(** [poll_single fd rd wr pri tmo]: Polls a single descriptor for the
events given by [rd], [wr], and [pri]. In [tmo] the timeout can be
passed. Returns [true] if one of the requested events is indicated
for the descriptor. The [EINTR] case is not handled.
*)
(** Actually, [poll_req_events] and [poll_act_events] are integers that
are bitmasks of some constants. The following functions allow access to
this detail.
*)
val int_of_req_events : poll_req_events -> int
val int_of_act_events : poll_act_events -> int
val req_events_of_int : int -> poll_req_events
val act_events_of_int : int -> poll_act_events
val const_rd_event : int
val const_wr_event : int
val const_pri_event : int
val const_err_event : int
val const_hup_event : int
val const_nval_event : int
(** {1 Event aggregation} *)
(** Support for "high-speed" poll implementations. Currently, only
[epoll] for Linux is supported.
The model exhibited in this API is the smallest common denominator
of Linux epoll, BSD kqueue, and Solaris ports. The [event_aggregator]
represents the set of monitored event sources. There is, so far,
only one source, namely file descriptors, i.e. one can check whether
a descriptor is readable or writable (like [poll]). The source can
be added to the [event_aggregator] to monitor the source.
By calling [poll_event_sources] one can determine sources that
are currently active (i.e. in signalling state).
It is undefined what happens when a file descriptor is closed while
being member of the aggregator.
*)
type event_aggregator
type event_source
val have_event_aggregation : unit -> bool
(** Whether there is an implementation for this OS *)
val create_event_aggregator : bool -> event_aggregator
(** [create_event_aggregator is_interruptible]: Creates a new aggregator,
and allocates the required OS resources.
If [is_interruptible], the aggregator can be interrupted from a
different thread. See [interrupt_event_aggregator] below.
*)
val destroy_event_aggregator : event_aggregator -> unit
(** Frees all OS resources *)
val fd_event_source : Unix.file_descr -> poll_req_events -> event_source
(** Wraps a file descriptor as event_source, and monitors the
events in [poll_req_events].
The [event_source] contains
state about the relation to the aggregator, and because of this,
the [event_source] should only be used together with one aggregator
(at a time).
*)
val modify_fd_event_source : event_source -> poll_req_events -> unit
(** Modifies the set of events monitored at this event source *)
val get_fd_of_event_source : event_source -> Unix.file_descr
(** Get the file descriptor wrapped by this event source *)
val act_events_of_event_source : event_source -> poll_act_events
(** Return the actual events of the source. This is updated when
[poll_event_sources] returns the source.
*)
val add_event_source : event_aggregator -> event_source -> unit
(** Adds the event source to the aggregator *)
val del_event_source : event_aggregator -> event_source -> unit
(** Removes the source from the aggregator *)
val interrupt_event_aggregator : event_aggregator -> unit
(** If [create_event_aggregator] was called with [true] as argument, the
aggregator is interruptible, and this function interrupts it. The
effect is that a currently running [poll_event_sources], or, if
it is not running, the next invocation of [poll_event_sources]
returns immediately.
If the aggregator is not interruptible, this function is a NOP.
*)
val push_event_updates : event_aggregator -> unit
(** Pushes all modifications of the sources to the kernel *)
val poll_event_sources : event_aggregator -> float -> event_source list
(** [poll_event_sources ea tmo]: First, all modifications are pushed
to the kernel, and polling is set up to get events. If no events
can currently be delivered, the function waits up to [tmo] seconds
(or endlessly if negative) for events. The function returns only a
limited number of events at a time. It is allowed that the function
returns fewer events than are currently in signalled state, even
none.
Call the function with [tmo=0.0] for non-blocking behavior.
Note that this is the "level-triggered" behavior: If a source
remains active it will be reported again by the next [poll_event_sources],
just as [poll] would do.
*)
val event_aggregator_fd : event_aggregator -> Unix.file_descr
(** Returns the underlying file descriptor. It is implementation-defined
whether this descriptor can also be polled for events. Generally,
you should run [push_event_updates] before polling from the descriptor.
*)
(* BSD: kqueue
Solaris: ports (port_create, port_associate)
*)
(** {1 Fork helpers} *)
(** Ocamlnet invokes [Unix.fork] at some places to create child processes
for doing real work. The following functions
allow it to register a handler that is run in the forked child
process. Note that this is done by the O'caml code calling [fork],
and not via the POSIX [atfork()] facility.
The handler should release OS resources like file descriptors that
are by default shared with the parent process.
The handler are not invoked when the only purpose of the [fork] is
to [exec] a different process.
*)
(** A [post_fork_handler] is a named function [unit -> unit] *)
class type post_fork_handler =
object
method name : string
method run : unit -> unit
end
val register_post_fork_handler : post_fork_handler -> unit
(** Registers a new post fork handler (MT-Safe) *)
val remove_post_fork_handler : post_fork_handler -> unit
(** Removes a post fork handler from the registry (MT-Safe) *)
val run_post_fork_handlers : unit -> unit
(** Runs all post fork handlers. Exceptions are caught and printed to
stderr.
*)
(** {1 Fork+exec} *)
(** The following function has some similarity with posix_spawn, but
is extended to our needs, Only special (although frequent) cases
are implemented with posix_spawn.
*)
type wd_spec =
| Wd_keep
(** Keep the current working directory in the spawned process *)
| Wd_chdir of string
(** Change to this directory in the spawned process *)
| Wd_fchdir of Unix.file_descr
(** Change to the directory which has been previously been opened *)
type pg_spec =
| Pg_keep
(** The new process will be member of the same process group as
this process *)
| Pg_new_bg_group
(** A new background process group is created, and the spawned
process will be its single member
*)
| Pg_new_fg_group
(** A new foreground process group is created, and the spawned
process will be its single member
*)
| Pg_join_group of int
(** The spawned process will be member of this process group *)
type fd_action =
| Fda_close of Unix.file_descr
(** Close the descriptor *)
| Fda_close_ignore of Unix.file_descr
(** Close the descriptor but ignore [EBADF] errors *)
| Fda_close_except of bool array
(** Closes all descriptors except those for which
[except.(k)] is true where [k = int_of_file_descr fd].
Descriptors outside the array index range are closed.
*)
| Fda_dup2 of Unix.file_descr * Unix.file_descr
(** Duplicate the first descriptor to the second as [dup2] does *)
type sig_action =
| Sig_default of int
(** Resets this signal to default behavior in the spawned process *)
| Sig_ignore of int
(** Ignores the signal in the spawned process *)
| Sig_mask of int list
(** Set the signal mask in the spawned process *)
val spawn : ?chdir:wd_spec ->
?pg:pg_spec ->
?fd_actions:fd_action list ->
?sig_actions:sig_action list ->
?env:string array ->
?no_posix_spawn:bool ->
string -> string array ->
int
(** [spawn cmd args]: Fork the process and exec [cmd] which gets the
arguments [args]. On success, the PID of the new process is returned.
This function does not wait for the completion of the process; use
[Unix.waitpid] for this purpose.
- [chdir]: If set, the new process starts with this working directory
(this is done before anything else)
- [pg]: If set, the new process will be a member of this process group
- [fd_actions]: If set, these descriptor actions are executed
sequentially
- [sig_actions]: If set, these signal actions are executed sequentially
- [env]: If set, the process gets this environment instead of the
current one
- [no_posix_spawn]: If set, the [posix_spawn] family of library
functions is not used to spawn even if possible, and always a
[fork/exec] approach is taken. This may be slower, but there is
normally better error reporting.
Any exceptions in the subprocess are detected, and reported. However,
if [Fda_close_ignore] leads to [EBADF] for a descriptor, this error is
ignored.
If [pg=Pg_new_fg_group], one should include [Sig_ignore Sys.sigttou]
in [sig_actions].
There are two implementations for [spawn]: One calls [fork] and [exec]
directly, and one uses the [posix_spawn] family of library functions.
The latter is faster on certain conditions, but this is very OS-specific.
A number of features are not supported by [posix_spawn] and will force
that [fork/exec] is used: [Wd_chdir], [Wd_fchdir], [Pg_new_fg_group],
and [Sig_ignore]. However, note some implementations of [posix_spawn]
also fall back to [fork/exec] internally for some combinations of flags,
and it is hard to predict which spawn calls can actually be accelerated.
The tendency, though, is that recent OS have sped up [posix_spawn]
so far possible (e.g. by using [vfork] internally, or even by making
[posix_spawn] a system call).
*)
(** {1 Notification via file descriptor events} *)
(** Often, it is advantageous to report asynchronous events via
file descriptors. On Linux, this is available via the [eventfd]
system call. On other platforms, pipes are used for emulation.
A [not_event] can have two states: off and on. Initially, the
[not_event] is off. By signalling it, the state changes to on,
and the underlying real file descriptor becomes readable.
By consuming the event, the state is switched back to off.
Note that a similar API exists for Win32: See {!Netsys_win32.w32_event}.
*)
type not_event
val create_event : unit -> not_event
(** Creates a new event file descriptor. *)
external set_nonblock_event : not_event -> unit
= "netsys_set_nonblock_not_event"
(** Sets the event fd to non-blocking mode *)
val get_event_fd : not_event -> Unix.file_descr
(** Returns a duplicate of the underlying file descriptor. This should only
be used for one thing: checking whether the desciptor becomes readable.
As this is a duplicate, the caller has to close the descriptor.
*)
external set_event : not_event -> unit = "netsys_set_not_event"
(** Signals the event *)
external wait_event : not_event -> unit = "netsys_wait_not_event"
(** If the event fd is not signalled, the function blocks until
it gets signalled, even in non-blocking mode.
*)
external consume_event : not_event -> unit = "netsys_consume_not_event"
(** Consumes the event, and switches the event fd to off again.
If the event fd is not signalled, the function blocks until
it gets signalled (in blocking mode), or it raises [EAGAIN]
or [EWOULDBLOCK] (in non-blocking mode).
This is effectively an atomic "wait-and-reset" operation.
*)
val destroy_event : not_event -> unit
(** Releases the OS resources. Note that there can be a hidden second
file descriptor, so closing the descriptor returned by [get_event_fd]
is not sufficient.
*)
val report_signal_as_event : not_event -> int -> unit
(** [report_signal_as_event ev sig] Installs a new signal handler for
signal [sig] so that [ev] is signalled when a signal arrives.
*)
(** {1 Notification queues} *)
(** Unimplemented, but a spec exists. Notification queues are intended
for forwarding events from C level to OCaml level. Possible uses:
- POSIX timers
- Realtime signals
- Subprocess monitoring
- AIO completion
*)
(*
(** This is a helper data structure only. This type of queue is a FIFO
implemented in C. When the queue is filled with data, a notification
mechanism is triggered to inform user code. Note that the notification
only happens when the first element is added to an empty queue, but not when
more elements are added. Also note that there can only be one notification
mechanism.
Only C code can add new elements!
*)
*)
(*
type 'a not_queue
val create_nqueue : unit -> 'a not_queue
(** create a new notification queue *)
val nqueue_length : 'a not_queue -> int
(** returns the number of elements in the queue *)
val nqueue_take : 'a not_queue -> 'a
(** takes the front element off the queue and returns it.
Raises [Not_found] if the queue is empty
*)
val nqueue_reset_notification : 'a not_queue -> unit
(** Do not notify *)
val nqueue_notify_via_event : 'a not_queue -> not_event -> unit
(** Arranges that the event is signalled when the first element is added
to the queue
*)
val nqueue_notify_via_condition : 'a not_queue -> Condition.t -> unit
(** Arranges that the condition variable is signalled when the first
element is added to the queue
*)
(** Another notification mechanism is described in {!Netsys_posix.sem_not}. *)
*)
(** {1 Subprocesses and signals} *)
(** Watching subprocesses requires that the right signal handler is
installed: [install_subprocess_handler]
*)
type watched_subprocess
val watch_subprocess : int -> int -> bool ->
Unix.file_descr * watched_subprocess
(** [let fd, ws = watch_subprocess pid pgid kill_flag]:
Enters the subprocess [pid]
into the watch list. If [pgid > 0], the process group ID is
[pgid] (for [killpg_subprocess] and [killpg_all_subprocesses]).
The [kill_flag] controls the process selection of
[kill_all_subprocesses] and [killpg_all_subprocesses].
The returned descriptor [fd] is open for reading and
will indicate EOF when the subprocess is terminated. Via [ws]
it is possible to query information about the subprocess. The
installed signal handler will [wait] for the subprocess and
put the process status into [ws].
The caller has to close [fd] after the termination is signaled.
*)
val ignore_subprocess : watched_subprocess -> unit
(** Changes the arrangement so that the termination of the subprocess
is no longer reported by the file descriptor. The file descriptor
indicates EOF immediately (and can be closed by the caller).
Nevertheless, the signal handler still [wait]s for the subprocess
to avoid zombies.
Any further access to [ws] will fail.
*)
val forget_subprocess : watched_subprocess -> unit
(** Frees OS resources. Any further access to the [ws] will fail. *)
val get_subprocess_status : watched_subprocess -> Unix.process_status option
(** If the subprocess is terminated, this function returns the status.
Otherwise [None] is returned
*)
val kill_subprocess : int -> watched_subprocess -> unit
(** Sends this signal to the subprocess if this process still exists.
Never throws an exception.
*)
val killpg_subprocess : int -> watched_subprocess -> unit
(** Sends this signal to the process group of the subprocess if there
is still a watched subprocess belonging to this group.
Never throws an exception.
*)
val kill_all_subprocesses : int -> bool -> bool -> unit
(** [kill_all_subprocess signal override nogroup]:
Sends a signal to potentially
all subprocesses. The signal is sent to a watched process if the process
still exists, and these two conditions hold both:
- [not nogroup || pgid = 0]: Processes with [pgid > 0] are excluded
if [nogroup] is set
- [kill_flag || override]: A process needs to have
[kill_flag] set, or [override] is specified
Never throws an exception if the signal handler is installed.
*)
val killpg_all_subprocesses : int -> bool -> unit
(** [killpg_all_subprocess signal override]: Sends a signal to potentially
all subprocesses belonging to a process group (i.e. [pgid>0]).
. The signal is sent to a process group if there are still watched
subprocesses
belonging to the group, and if either the [kill_flag] of any of the
subprocesses process was set to [true], or [override] is [true].
Never throws an exception if the signal handler is installed.
*)
val install_subprocess_handler : unit -> unit
(** Installs a SIGCHLD handler for watching subprocesses. Note that only
processes are [wait]ed for that are registered with
[watch_subprocess].
The handler works both in the single-threaded and the multi-threaded
case. [install_subprocess_handler] can safely called several times.
The handler is installed every time the function is called, but the
required data structures are only initialized at the first call.
*)
val register_subprocess_handler : unit -> unit
(** Uses the {!Netsys_signal} framework to manage the installation of
the SIGCHLD handler.
This is the preferred method of installing the SIGCHLD handler.
*)
(** {b Further notes.} *)
(** The subprocess handler and [fork()]: The subprocess handler uses
pipes for notification, and because of this it is sensitive to
unpredicted duplicates of the pipe descriptors. [fork()] duplicates
these pipe descriptors. If nothing is done about this issue, it
can happen that the notification does not work anymore as it relies
on detecting closed pipes.
If [fork()] is immediately followed by [exec()] (as it is done
to run subcommands), the problem does not occur, because the relevant
descriptors are closed at [exec()] time.
If [fork()] is used to start worker processes, however, we have
to be careful. The descriptors need to be closed, so that the
parent can continue to monitor subprocesses, and to allow the worker
processes to use this mechanism. This module defines post fork
handlers (see above), and a handler is automatically added that
cleans the descriptors up. All user code has to do is to call
[run_post_fork_handlers] immediately after [fork()] has spawned
the new child, from the new child. This completely resets
everything.
*)
(** The subprocess handler and multi-threading: The handler has been
carefully designed, and works even in multi-threaded programs.
However, one should know that multi-threading and [fork()] do not
interact well with each other. Again, the problems do not occur
if [fork()] is followed by [exec()]. There is no solution for the
case that worker processes are started with [fork()], though.
The (very generic) problem is that the state of mutexes and other
multi-threading primitives is not well-defined after a [fork()].
*)
(** {1 Syslog} *)
type level = Netlog.level
(* [ `Emerg | `Alert | `Crit | `Err | `Warning | `Notice | `Info | `Debug ]
*)
(** The log levels *)
type syslog_facility =
[ `Authpriv
| `Cron
| `Daemon
| `Ftp
| `Kern
| `Local0
| `Local1
| `Local2
| `Local3
| `Local4
| `Local5
| `Local6
| `Local7
| `Lpr
| `Mail
| `News
| `Syslog
| `User
| `Uucp
| `Default
]
(** The facilities. Only [`User] and [`Local0] to [`Local7] are
standard POSIX. If a facility is unavailable it is silently
substituted by [`Local0]. The value [`Default] leaves this unspecified.
*)
type syslog_option =
[ `Cons
| `Ndelay
| `Odelay
| `Nowait
| `Pid
]
(** The syslog options:
- [`Cons]: Fall back to console logging if syslog is unavailable
- [`Ndelay]: Open the connection immediately
- [`Odelay]: Open the connection at the first call [syslog] (default)
- [`Nowait]: Do not wait until it is ensured that the message is
sent
- [`Pid]: Log the PID with every message
*)
val openlog : string option -> syslog_option list -> syslog_facility -> unit
(** [openlog ident options facility]: Opens a log stream. [ident] is
prepended to every message if given (usually the program name).
The [facility] is the default facility for [syslog] calls.
*)
val syslog : syslog_facility -> level -> string -> unit
(** [syslog facility level message]: Logs [message] at [level] for
[facility]
*)
val closelog : unit -> unit
(** Closes the log stream *)
(** Usually, the log stream is redirected to syslog by either:
- setting [Netlog.current_logger] to [syslog facility], e.g.
{[ Netlog.current_logger := Netsys_posix.syslog `User ]}
- using the Netplex class for sending message to syslog (XXX)
*)
(** {1 Sync} *)
external fsync : Unix.file_descr -> unit = "netsys_fsync"
(** Sync data and metadata to disk *)
external fdatasync : Unix.file_descr -> unit = "netsys_fdatasync"
(** Syncs only data to disk. If this is not implemented, same effect
as [fsync]
*)
(** {1 Sending file descriptors over Unix domain sockets} *)
(** These functions can be used to send file descriptors from one process
to another one. The descriptor [sock] must be a connected
Unix domain socket.
The functionality backing this is non-standard but widely available.
{b Not yet implemented, but spec exists.}
*)
(*
val have_scm_rights : unit -> bool
(** Whether this functionality is available *)
val send_fd : Unix.file_descr -> Unix.file_descr -> unit
(** [send_fd sock fd]: Sends [fd] via [sock] as ancillary message.
Also sends a single byte 'X' over the main message channel.
*)
val receive_fd : Unix.file_descr -> Unix.file_descr
(** [receive_fd sock]: Receives a single byte over the main message
channel, and checks whether a file descriptor accompanies the
byte. If so, it is returned. If not, the function will raise [Not_found].
*)
*)
(** {1 Optional POSIX functions} *)
external have_fadvise : unit -> bool = "netsys_have_posix_fadvise"
(** Returns whether the OS supports the fadvise POSIX option *)
type advice =
| POSIX_FADV_NORMAL
| POSIX_FADV_SEQUENTIAL
| POSIX_FADV_RANDOM
| POSIX_FADV_NOREUSE
| POSIX_FADV_WILLNEED
| POSIX_FADV_DONTNEED
| FADV_NORMAL
| FADV_SEQUENTIAL
| FADV_RANDOM
| FADV_NOREUSE
| FADV_WILLNEED
| FADV_DONTNEED
(** Possible advices for fadvise. The names starting with "POSIX_" and
the ones lacking the prefix have the same meaning. In new code,
the names starting with "POSIX_" should be preferred (for better
compaibility with other libraries).
*)
external fadvise : Unix.file_descr -> int64 -> int64 -> advice -> unit
= "netsys_fadvise"
(** Advises to load pages into the page table from the file, or to remove
such pages.
*)
external have_fallocate : unit -> bool = "netsys_have_posix_fallocate"
(** Returns whether the OS supports the fallocate POSIX option *)
external fallocate : Unix.file_descr -> int64 -> int64 -> unit
= "netsys_fallocate"
(** Allocate space for the file and the specified file region *)
(** {1 POSIX Shared Memory} *)
external have_posix_shm : unit -> bool = "netsys_have_posix_shm"
(** Returns whether the OS supports POSIX shared memory *)
type shm_open_flag =