123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136openCoreopenImportopenFile_descr_watcher_intfopenRead_write_pair.ExportmoduleTable=Bounded_int_tabletypet={descr_tables:(File_descr.t,unit)Table.tRead_write_pair.t;handle_fd_read_ready:File_descr.t->unit;handle_fd_read_bad:File_descr.t->unit;handle_fd_write_ready:File_descr.t->unit;handle_fd_write_bad:File_descr.t->unit}[@@derivingsexp_of]letbackend=Config.File_descr_watcher.Selectletinvariantt:unit=tryRead_write_pair.itert.descr_tables~f:(Table.invariantignoreignore)with|exn->raise_s[%message"Select_file_descr_watcher.invariant failed"(exn:exn)~select_file_descr_watcher:(t:t)];;type'aadditional_create_args=handle_fd_read_bad:(File_descr.t->unit)->handle_fd_write_bad:(File_descr.t->unit)->'aletcreate~handle_fd_read_bad~handle_fd_write_bad~num_file_descrs~handle_fd_read_ready~handle_fd_write_ready={descr_tables=Read_write_pair.create_fn(fun()->Table.create~num_keys:num_file_descrs~key_to_int:File_descr.to_int~sexp_of_key:File_descr.sexp_of_t());handle_fd_read_ready;handle_fd_read_bad;handle_fd_write_ready;handle_fd_write_bad};;letreset_in_forked_process_=()letitert~f=Read_write_pair.iterit.descr_tables~f:(funread_or_writetable->Table.iteritable~f:(fun~key~data:_->fkeyread_or_write));;modulePre=structtypet=File_descr.tlistRead_write_pair.t[@@derivingsexp_of]endletsettfile_descrdesired=Read_write_pair.iterit.descr_tables~f:(funread_or_writetable->ifRead_write_pair.getdesiredread_or_writethenTable.settable~key:file_descr~data:()elseTable.removetablefile_descr);`Ok;;letpre_checkt=Read_write_pair.mapt.descr_tables~f:Table.keysmoduleCheck_result=structtypet={pre:Pre.t;select_result:(Unix.Select_fds.t,exn)Result.t}[@@derivingsexp_of]endletthread_safe_check(typea)(_:t)(pre:Pre.t)(timeout:aTimeout.t)(span:a)=lettimeout=matchtimeoutwith|Immediately->`Immediately(* Wait no longer than one second, which avoids any weirdness due to feeding large
timeouts to select. *)|After->`After(Time_ns.Span.minspanTime_ns.Span.second)in{Check_result.pre;select_result=Result.try_with(fun()->Unix.select~read:pre.read~write:pre.write~except:[]~timeout())};;letpost_checkt({Check_result.pre;select_result}ascheck_result)=trymatchselect_resultwith(* We think 514 should be treated like EINTR. *)|Error(Unix.Unix_error((EINTR|EUNKNOWNERR514),_,_))->()|Ok{read;write;except}->assert(List.is_emptyexcept);List.iterwrite~f:t.handle_fd_write_ready;List.iterread~f:t.handle_fd_read_ready|Error(Unix.Unix_error(EBADF,_,_))->letbadread_or_write=letfds=matchread_or_writewith|`Read->pre.read|`Write->pre.writeinList.foldfds~init:[]~f:(funacfile_descr->matchSyscall.syscall(fun()->ignore(Unix.fstatfile_descr:Unix.stats))with|Ok()->ac|Error(Unix.Unix_error(EBADF,_,_))->file_descr::ac|Errorexn->raise_s[%message"fstat raised unexpected exn"(file_descr:File_descr.t)(exn:exn)])inList.iter(bad`Write)~f:t.handle_fd_write_bad;List.iter(bad`Read)~f:t.handle_fd_read_bad|Errorexn->raise_s[%message"select raised unexpected exn"~_:(exn:exn)]with|exn->raise_s[%message"File_descr_watcher.post_check bug"(exn:exn)(check_result:Check_result.t)~select_file_descr_watcher:(t:t)];;