diff --git a/exec.cpp b/exec.cpp index 840aa7ab1..6794fb54b 100644 --- a/exec.cpp +++ b/exec.cpp @@ -160,7 +160,7 @@ static bool use_fd_in_pipe(int fd, const io_chain_t &io_chain) { for (size_t idx = 0; idx < io_chain.size(); idx++) { - const shared_ptr &io = io_chain.at(idx); + const io_data_t *io = io_chain.at(idx); if ((io->io_mode == IO_BUFFER) || (io->io_mode == IO_PIPE)) { @@ -378,8 +378,8 @@ static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t &out_chain, s for (size_t idx = 0; idx < in_chain.size(); idx++) { - const shared_ptr &in = in_chain.at(idx); - shared_ptr out; //gets allocated via new + io_data_t *in = in_chain.at(idx); + io_data_t *out = NULL; //gets allocated via new switch (in->io_mode) { @@ -397,7 +397,7 @@ static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t &out_chain, s case IO_BUFFER: case IO_CLOSE: { - out = in; + out = new io_data_t(*in); break; } @@ -406,7 +406,7 @@ static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t &out_chain, s */ case IO_FILE: { - out.reset(new io_data_t()); + out = new io_data_t(); out->fd = in->fd; out->io_mode = IO_FD; out->param2.close_old = 1; @@ -544,7 +544,7 @@ static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *proce bool result = true; for (size_t idx = 0; idx < job->io.size(); idx++) { - const shared_ptr &io = job->io.at(idx); + const io_data_t *io = job->io.at(idx); if (io->io_mode == IO_FILE) { const char *path = io->filename_cstr; @@ -567,7 +567,9 @@ void exec(parser_t &parser, job_t *j) int mypipe[2]; sigset_t chldset; - shared_ptr io_buffer; + io_data_t pipe_read, pipe_write; + + io_data_t *io_buffer =0; /* Set to true if something goes wrong while exec:ing the job, in @@ -595,7 +597,7 @@ void exec(parser_t &parser, job_t *j) io_duplicate_prepend(parser.block_io, j->io); } - shared_ptr input_redirect; + const io_data_t *input_redirect = NULL; for (size_t idx = 0; idx < j->io.size(); idx++) { input_redirect = j->io.at(idx); @@ -644,19 +646,17 @@ void exec(parser_t &parser, job_t *j) } - shared_ptr pipe_read(new io_data_t); - pipe_read->fd = 0; - pipe_read->io_mode = IO_PIPE; - pipe_read->is_input = 1; - pipe_read->param1.pipe_fd[0] = pipe_read->param1.pipe_fd[1] = -1; + pipe_read.fd = 0; + pipe_read.io_mode = IO_PIPE; + pipe_read.is_input = 1; + pipe_read.param1.pipe_fd[0] = pipe_read.param1.pipe_fd[1] = -1; - shared_ptr pipe_write(new io_data_t); - pipe_write->fd = 1; - pipe_write->io_mode = IO_PIPE; - pipe_write->is_input = 0; - pipe_write->param1.pipe_fd[0] = pipe_write->param1.pipe_fd[1] = -1; + pipe_write.fd = 1; + pipe_write.io_mode = IO_PIPE; + pipe_write.is_input = 0; + pipe_write.param1.pipe_fd[0] = pipe_write.param1.pipe_fd[1] = -1; - j->io.push_back(pipe_write); + j->io.push_back(&pipe_write); signal_block(); @@ -728,9 +728,9 @@ void exec(parser_t &parser, job_t *j) const bool p_wants_pipe = (p->next != NULL); mypipe[1]=-1; - pipe_write->fd = p->pipe_write_fd; - pipe_read->fd = p->pipe_read_fd; -// debug( 0, L"Pipe created from fd %d to fd %d", pipe_write->fd, pipe_read->fd ); + pipe_write.fd = p->pipe_write_fd; + pipe_read.fd = p->pipe_read_fd; +// debug( 0, L"Pipe created from fd %d to fd %d", pipe_write.fd, pipe_read.fd ); /* @@ -752,7 +752,7 @@ void exec(parser_t &parser, job_t *j) if (p == j->first_process->next) { - j->io.push_back(pipe_read); + j->io.push_back(&pipe_read); } if (p_wants_pipe) @@ -767,7 +767,7 @@ void exec(parser_t &parser, job_t *j) break; } - memcpy(pipe_write->param1.pipe_fd, mypipe, sizeof(int)*2); + memcpy(pipe_write.param1.pipe_fd, mypipe, sizeof(int)*2); } else { @@ -775,7 +775,7 @@ void exec(parser_t &parser, job_t *j) This is the last element of the pipeline. Remove the io redirection for pipe output. */ - io_chain_t::iterator where = std::find(j->io.begin(), j->io.end(), pipe_write); + io_chain_t::iterator where = std::find(j->io.begin(), j->io.end(), &pipe_write); if (where != j->io.end()) j->io.erase(where); } @@ -830,7 +830,7 @@ void exec(parser_t &parser, job_t *j) if (p->next) { - io_buffer.reset(io_buffer_create(0)); + io_buffer = io_buffer_create(0); j->io.push_back(io_buffer); } @@ -847,7 +847,7 @@ void exec(parser_t &parser, job_t *j) { if (p->next) { - io_buffer.reset(io_buffer_create(0)); + io_buffer = io_buffer_create(0); j->io.push_back(io_buffer); } @@ -869,7 +869,7 @@ void exec(parser_t &parser, job_t *j) */ if (p == j->first_process) { - const shared_ptr &in = io_chain_get(j->io, 0); + const io_data_t *in = io_chain_get(j->io, 0); if (in) { @@ -935,7 +935,7 @@ void exec(parser_t &parser, job_t *j) } else { - builtin_stdin = pipe_read->param1.pipe_fd[0]; + builtin_stdin = pipe_read.param1.pipe_fd[0]; } if (builtin_stdin == -1) @@ -1035,7 +1035,7 @@ void exec(parser_t &parser, job_t *j) io_remove(j->io, io_buffer); - io_buffer_read(io_buffer.get()); + io_buffer_read(io_buffer); const char *buffer = io_buffer->out_buffer_ptr(); size_t count = io_buffer->out_buffer_size(); @@ -1083,7 +1083,7 @@ void exec(parser_t &parser, job_t *j) io_buffer_destroy(io_buffer); - io_buffer.reset(); + io_buffer=0; break; } @@ -1154,7 +1154,7 @@ void exec(parser_t &parser, job_t *j) performance quite a bit in complex completion code. */ - const shared_ptr &io = io_chain_get(j->io, 1); + io_data_t *io = io_chain_get(j->io, 1); bool buffer_stdout = io && io->io_mode == IO_BUFFER; if ((get_stderr_buffer().empty()) && @@ -1183,7 +1183,7 @@ void exec(parser_t &parser, job_t *j) for (io_chain_t::iterator iter = j->io.begin(); iter != j->io.end(); iter++) { - const shared_ptr &tmp_io = *iter; + io_data_t *tmp_io = *iter; if (tmp_io->io_mode == IO_FILE && strcmp(tmp_io->filename_cstr, "/dev/null") != 0) { skip_fork = false; @@ -1357,14 +1357,14 @@ void exec(parser_t &parser, job_t *j) Close the pipe the current process uses to read from the previous process_t */ - if (pipe_read->param1.pipe_fd[0] >= 0) - exec_close(pipe_read->param1.pipe_fd[0]); + if (pipe_read.param1.pipe_fd[0] >= 0) + exec_close(pipe_read.param1.pipe_fd[0]); /* Set up the pipe the next process uses to read from the current process_t */ if (p_wants_pipe) - pipe_read->param1.pipe_fd[0] = mypipe[0]; + pipe_read.param1.pipe_fd[0] = mypipe[0]; /* If there is a next process in the pipeline, close the @@ -1392,7 +1392,7 @@ void exec(parser_t &parser, job_t *j) debug(3, L"Job is constructed"); - io_remove(j->io, pipe_read); + io_remove(j->io, &pipe_read); for (io_chain_t::const_iterator iter = parser.block_io.begin(); iter != parser.block_io.end(); iter++) { @@ -1419,6 +1419,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst) ASSERT_IS_MAIN_THREAD(); int prev_subshell = is_subshell; int status, prev_status; + io_data_t *io_buffer; char sep=0; const env_var_t ifs = env_get_string(L"IFS"); @@ -1438,8 +1439,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst) } is_subshell=1; - - const shared_ptr io_buffer(io_buffer_create(0)); + io_buffer= io_buffer_create(0); prev_status = proc_get_last_status(); @@ -1453,7 +1453,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst) status = proc_get_last_status(); } - io_buffer_read(io_buffer.get()); + io_buffer_read(io_buffer); proc_set_last_status(prev_status); diff --git a/io.cpp b/io.cpp index 6a304014c..ef2a0493f 100644 --- a/io.cpp +++ b/io.cpp @@ -133,7 +133,7 @@ io_data_t *io_buffer_create(bool is_input) return buffer_redirect; } -void io_buffer_destroy(const shared_ptr &io_buffer) +void io_buffer_destroy(io_data_t *io_buffer) { /** @@ -151,9 +151,10 @@ void io_buffer_destroy(const shared_ptr &io_buffer) Dont free fd for writing. This should already be free'd before calling exec_read_io_buffer on the buffer */ + delete io_buffer; } -void io_chain_t::remove(const shared_ptr &element) +void io_chain_t::remove(const io_data_t *element) { // See if you can guess why std::find doesn't work here for (io_chain_t::iterator iter = this->begin(); iter != this->end(); ++iter) @@ -166,22 +167,48 @@ void io_chain_t::remove(const shared_ptr &element) } } +io_chain_t io_chain_t::duplicate() const +{ + io_chain_t result; + result.reserve(this->size()); + for (io_chain_t::const_iterator iter = this->begin(); iter != this->end(); iter++) + { + const io_data_t *io = *iter; + result.push_back(new io_data_t(*io)); + } + return result; +} + void io_chain_t::duplicate_prepend(const io_chain_t &src) { - /* Prepend a duplicate of src before this. */ - this->insert(this->begin(), src.begin(), src.end()); + /* Prepend a duplicate of src before this. Start by inserting a bunch of NULLs (so we only have to reallocate once) and then replace them. */ + this->insert(this->begin(), src.size(), NULL); + for (size_t idx = 0; idx < src.size(); idx++) + { + const io_data_t *src_data = src.at(idx); + this->at(idx) = new io_data_t(*src_data); + } } void io_chain_t::destroy() { + for (size_t idx = 0; idx < this->size(); idx++) + { + delete this->at(idx); + } this->clear(); } -void io_remove(io_chain_t &list, const shared_ptr &element) +void io_remove(io_chain_t &list, const io_data_t *element) { list.remove(element); } +io_chain_t io_duplicate(const io_chain_t &chain) +{ + return chain.duplicate(); +} + void io_print(const io_chain_t &chain) { if (chain.empty()) @@ -193,7 +220,7 @@ void io_print(const io_chain_t &chain) fprintf(stderr, "Chain %p (%ld items):\n", &chain, (long)chain.size()); for (size_t i=0; i < chain.size(); i++) { - const shared_ptr &io = chain.at(i); + const io_data_t *io = chain.at(i); fprintf(stderr, "\t%lu: fd:%d, input:%s, ", (unsigned long)i, io->fd, io->is_input ? "yes" : "no"); switch (io->io_mode) { @@ -227,51 +254,50 @@ void io_chain_destroy(io_chain_t &chain) } /* Return the last IO for the given fd */ -shared_ptr io_chain_t::get_io_for_fd(int fd) const +const io_data_t *io_chain_t::get_io_for_fd(int fd) const { size_t idx = this->size(); while (idx--) { - const shared_ptr &data = this->at(idx); + const io_data_t *data = this->at(idx); if (data->fd == fd) { return data; } } - return shared_ptr(); + return NULL; } -shared_ptr io_chain_t::get_io_for_fd(int fd) +io_data_t *io_chain_t::get_io_for_fd(int fd) { size_t idx = this->size(); while (idx--) { - const shared_ptr &data = this->at(idx); + io_data_t *data = this->at(idx); if (data->fd == fd) { return data; } } - return shared_ptr(); + return NULL; } /* The old function returned the last match, so we mimic that. */ -shared_ptr io_chain_get(const io_chain_t &src, int fd) +const io_data_t *io_chain_get(const io_chain_t &src, int fd) { return src.get_io_for_fd(fd); } -shared_ptr io_chain_get(io_chain_t &src, int fd) +io_data_t *io_chain_get(io_chain_t &src, int fd) { return src.get_io_for_fd(fd); } -io_chain_t::io_chain_t(const shared_ptr &data) : - std::vector >(1, data) +io_chain_t::io_chain_t(io_data_t *data) : std::vector(1, data) { } -io_chain_t::io_chain_t() : std::vector >() +io_chain_t::io_chain_t() : std::vector() { } diff --git a/io.h b/io.h index 34dc242bd..5b77838aa 100644 --- a/io.h +++ b/io.h @@ -20,10 +20,9 @@ private: /** buffer to save output in for IO_BUFFER. Note that in the original fish, the buffer was a pointer to a buffer_t stored in the param2 union down below, and when an io_data_t was duplicated the pointer was copied so that two io_data_ts referenced the same buffer. It's not clear to me how this was ever cleaned up correctly. But it's important that they share the same buffer for reasons I don't yet understand either. We can get correct sharing and cleanup with shared_ptr. */ shared_ptr > out_buffer; - /* No assignment or copying allowed */ - io_data_t(const io_data_t &rhs); + /* No assignment allowed */ void operator=(const io_data_t &rhs); - + public: /** Type of redirect */ int io_mode; @@ -108,32 +107,46 @@ public: { } + io_data_t(const io_data_t &rhs) : + out_buffer(rhs.out_buffer), + io_mode(rhs.io_mode), + fd(rhs.fd), + param1(rhs.param1), + param2(rhs.param2), + filename_cstr(rhs.filename_cstr ? strdup(rhs.filename_cstr) : NULL), + is_input(rhs.is_input) + { + } + ~io_data_t() { free((void *)filename_cstr); } }; -class io_chain_t : public std::vector > +class io_chain_t : public std::vector { public: io_chain_t(); - io_chain_t(const shared_ptr &); + io_chain_t(io_data_t *); - void remove(const shared_ptr &element); + void remove(const io_data_t *element); io_chain_t duplicate() const; void duplicate_prepend(const io_chain_t &src); void destroy(); - shared_ptr get_io_for_fd(int fd) const; - shared_ptr get_io_for_fd(int fd); + const io_data_t *get_io_for_fd(int fd) const; + io_data_t *get_io_for_fd(int fd); }; /** Remove the specified io redirection from the chain */ -void io_remove(io_chain_t &list, const shared_ptr &element); +void io_remove(io_chain_t &list, const io_data_t *element); + +/** Make a copy of the specified chain of redirections. Uses operator new. */ +io_chain_t io_duplicate(const io_chain_t &chain); /** Return a shallow copy of the specified chain of redirections that contains only the applicable redirections. That is, if there's multiple redirections for the same fd, only the second one is included. */ io_chain_t io_unique(const io_chain_t &chain); @@ -147,14 +160,14 @@ void io_chain_destroy(io_chain_t &chain); /** Return the last io redirection in the chain for the specified file descriptor. */ -shared_ptr io_chain_get(const io_chain_t &src, int fd); -shared_ptr io_chain_get(io_chain_t &src, int fd); +const io_data_t *io_chain_get(const io_chain_t &src, int fd); +io_data_t *io_chain_get(io_chain_t &src, int fd); /** Free all resources used by a IO_BUFFER type io redirection. */ -void io_buffer_destroy(const shared_ptr &io_buffer); +void io_buffer_destroy(io_data_t *io_buffer); /** Create a IO_BUFFER type io redirection, complete with a pipe and a diff --git a/parser.cpp b/parser.cpp index f418df8c5..361c3d0f9 100644 --- a/parser.cpp +++ b/parser.cpp @@ -377,7 +377,7 @@ parser_t::parser_t(enum parser_type_t type, bool errors) : job_start_pos(0), eval_level(-1), current_block(NULL), - block_io(shared_ptr()) + block_io(NULL) { } @@ -1495,7 +1495,7 @@ void parser_t::parse_job_argument_list(process_t *p, case TOK_REDIRECT_NOCLOB: { int type = tok_last_type(tok); - shared_ptr new_io; + std::auto_ptr new_io; wcstring target; bool has_target = false; wchar_t *end; @@ -1633,7 +1633,7 @@ void parser_t::parse_job_argument_list(process_t *p, } } - j->io.push_back(new_io); + j->io.push_back(new_io.release()); } break; diff --git a/postfork.cpp b/postfork.cpp index ed8dfb9a4..495845e8b 100644 --- a/postfork.cpp +++ b/postfork.cpp @@ -117,7 +117,7 @@ static void free_redirected_fds_from_pipes(io_chain_t &io_chain) for (size_t j = 0; j < max; j++) { /* We're only interested in pipes */ - io_data_t *possible_conflict = io_chain.at(j).get(); + io_data_t *possible_conflict = io_chain.at(j); if (possible_conflict->io_mode != IO_PIPE && possible_conflict->io_mode != IO_BUFFER) continue; @@ -166,7 +166,7 @@ static int handle_child_io(io_chain_t &io_chain) free_redirected_fds_from_pipes(io_chain); for (size_t idx = 0; idx < io_chain.size(); idx++) { - io_data_t *io = io_chain.at(idx).get(); + io_data_t *io = io_chain.at(idx); int tmp; if (io->io_mode == IO_FD && io->fd == io->param1.old_fd) @@ -441,7 +441,7 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil for (size_t idx = 0; idx < j->io.size(); idx++) { - shared_ptr io = j->io.at(idx); + const io_data_t *io = j->io.at(idx); if (io->io_mode == IO_FD && io->fd == io->param1.old_fd) { diff --git a/proc.cpp b/proc.cpp index 1b37f1496..7ff41f4a8 100644 --- a/proc.cpp +++ b/proc.cpp @@ -869,7 +869,7 @@ static int select_try(job_t *j) for (size_t idx = 0; idx < j->io.size(); idx++) { - const io_data_t *d = j->io.at(idx).get(); + const io_data_t *d = j->io.at(idx); if (d->io_mode == IO_BUFFER) { int fd = d->param1.pipe_fd[0]; @@ -909,7 +909,7 @@ static void read_try(job_t *j) */ for (size_t idx = 0; idx < j->io.size(); idx++) { - io_data_t *d = j->io.at(idx).get(); + io_data_t *d = j->io.at(idx); if (d->io_mode == IO_BUFFER) { buff=d; diff --git a/reader.cpp b/reader.cpp index 6abde371a..592943395 100644 --- a/reader.cpp +++ b/reader.cpp @@ -1014,7 +1014,7 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector in(io_buffer_create(true)); + io_data_t *in = io_buffer_create(true); in->fd = 3; escaped_separator = escape(COMPLETE_SEP_STR, 1); @@ -1083,7 +1083,7 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector out(io_buffer_create(false)); + io_data_t *out = io_buffer_create(false); out->fd = 4; parser_t &parser = parser_t::principal_parser(); @@ -1093,7 +1093,7 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vectorout_buffer_append((char *)&nil, 1);