2021-05-12 03:01:08 +08:00
|
|
|
// Support for handling pids that are no longer fish jobs.
|
|
|
|
// This includes pids that have been disowned ("forgotten") and background jobs which have finished,
|
|
|
|
// but may be wait'ed.
|
|
|
|
#ifndef FISH_WAIT_HANDLE_H
|
|
|
|
#define FISH_WAIT_HANDLE_H
|
|
|
|
|
|
|
|
#include "config.h" // IWYU pragma: keep
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
/// The bits of a job necessary to support 'wait' and '--on-process-exit'.
|
|
|
|
/// This may outlive the job.
|
|
|
|
struct wait_handle_t {
|
2021-10-29 01:37:43 +08:00
|
|
|
/// Construct from a pid, job id, and base name.
|
|
|
|
wait_handle_t(pid_t pid, internal_job_id_t jid, wcstring name)
|
|
|
|
: pid(pid), internal_job_id(jid), base_name(std::move(name)) {}
|
2021-05-12 03:01:08 +08:00
|
|
|
|
|
|
|
/// The pid of this process.
|
2021-10-29 01:37:43 +08:00
|
|
|
const pid_t pid{};
|
2021-05-12 03:01:08 +08:00
|
|
|
|
2021-05-21 02:25:32 +08:00
|
|
|
/// The internal job id of the job which contained this process.
|
2021-10-29 01:37:43 +08:00
|
|
|
const internal_job_id_t internal_job_id{};
|
2021-05-21 02:25:32 +08:00
|
|
|
|
2021-05-12 03:01:08 +08:00
|
|
|
/// The "base name" of this process.
|
|
|
|
/// For example if the process is "/bin/sleep" then this will be 'sleep'.
|
2021-10-29 01:37:43 +08:00
|
|
|
const wcstring base_name{};
|
2021-05-12 03:01:08 +08:00
|
|
|
|
2021-05-18 06:22:02 +08:00
|
|
|
/// The value appropriate for populating $status, if completed.
|
|
|
|
int status{0};
|
|
|
|
|
2021-05-12 03:01:08 +08:00
|
|
|
/// Set to true when the process is completed.
|
|
|
|
bool completed{false};
|
|
|
|
};
|
|
|
|
using wait_handle_ref_t = std::shared_ptr<wait_handle_t>;
|
|
|
|
|
|
|
|
/// Support for storing a list of wait handles, with a max limit set at initialization.
|
|
|
|
/// Note this class is not safe for concurrent access.
|
2021-07-23 01:43:25 +08:00
|
|
|
class wait_handle_store_t : noncopyable_t {
|
2021-05-12 03:01:08 +08:00
|
|
|
public:
|
|
|
|
// Our wait handles are arranged in a linked list for its iterator invalidation semantics: we
|
|
|
|
// may remove one without needing to update the map from pid -> handle.
|
|
|
|
using wait_handle_list_t = std::list<wait_handle_ref_t>;
|
|
|
|
|
|
|
|
/// Construct with a max limit on the number of handles we will remember.
|
|
|
|
/// The default is 1024, which is zsh's default.
|
|
|
|
explicit wait_handle_store_t(size_t limit = 1024);
|
|
|
|
|
|
|
|
/// Add a wait handle to the store. This may remove the oldest handle, if our limit is exceeded.
|
|
|
|
/// It may also remove any existing handle with that pid.
|
|
|
|
/// For convenience, this does nothing if wh is null.
|
|
|
|
void add(wait_handle_ref_t wh);
|
|
|
|
|
|
|
|
/// \return the wait handle for a pid, or nullptr if there is none.
|
|
|
|
/// This is a fast lookup.
|
|
|
|
wait_handle_ref_t get_by_pid(pid_t pid) const;
|
|
|
|
|
|
|
|
/// Remove a given wait handle, if present in this store.
|
|
|
|
void remove(const wait_handle_ref_t &wh);
|
|
|
|
|
|
|
|
/// Remove the wait handle for a pid, if present in this store.
|
|
|
|
void remove_by_pid(pid_t pid);
|
|
|
|
|
|
|
|
/// Get the list of all wait handles.
|
|
|
|
const wait_handle_list_t &get_list() const { return handles_; }
|
|
|
|
|
|
|
|
/// Convenience to return the size, for testing.
|
|
|
|
size_t size() const { return handles_.size(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
using list_node_t = typename wait_handle_list_t::iterator;
|
|
|
|
|
|
|
|
/// The list of all wait handles. New ones come on the front, the last one is oldest.
|
|
|
|
wait_handle_list_t handles_{};
|
|
|
|
|
|
|
|
/// Map from pid to the wait handle's position in the list.
|
|
|
|
std::unordered_map<pid_t, list_node_t> handle_map_{};
|
|
|
|
|
|
|
|
/// Max supported wait handles.
|
|
|
|
const size_t limit_;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|