-
-
Notifications
You must be signed in to change notification settings - Fork 234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Append history in interactive sessions #99
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am sorry I did not review your patch on Trac. My time for MacPorts is currently a bit scarce, but the pull request makes it easier. Thank you for that.
The changes look good to me, although I did not test them. I would appreciate if you could use the usual trailer with "Closes: ..." as reference to the ticket.
src/pextlib1.0/readline.c
Outdated
|
||
hist_file = fopen(s, "a"); | ||
fprintf(hist_file, "%s\n", current_history()->line); | ||
fclose(hist_file); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a chance for a race condition here when multiple port instances are running at the same time. Although it is very unlikely that anyone would be able to type in both port instances at the same time, so we could just ignore it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@raimue Hmm, okay, I will see if I can address this with lockfiles or the like. If things get too hairy, I may just ignore it as you say.
No problem, I figured you were probably too busy to respond on Trac. I definitely understand not having time for things like Macports sometimes; real life can be a pain! But you're welcome, and thank you for the kindness.
Okay, I will try to do that in the future. Where am I supposed to put the "Closes: ..." remark? In the title of the PR? |
In the commit message body, on a line by itself. |
@jmroot Oh, okay. I had read that article previously, but I missed the part which gives an example of that. Thanks for pointing me to it! |
The only interesting thing here is that apparently we don't need the special encoding that is currently used in the history file. More details here: https://trac.macports.org/ticket/56381#comment:10
Hitherto, port.tcl has used bash-style history-writing at the end of an interactive session. That is vulnerable to crashes and other abrupt interruptions. This changes that.
As discussed here: macports#99 (comment) The first hunk which changes _XOPEN_SOURCE to _BSD_SOURCE is due to the fact that flock(2) doesn't work when _XOPEN_SOURCE is defined as such. According to an answer on StackOverflow, using _BSD_SOURCE is a valid alternative for strdup(3). See https://stackoverflow.com/questions/5378778/what-does-d-xopen-source-do-mean#5724485
f5683ea
to
bc55bfd
Compare
@raimue I have added some file-locking code as discussed above. Sorry for the delay; I've been quite busy but finally managed to make some time for this. Please let me know if anything else should be done. Also, should I squash my commits into a single one to have the "Closes: ..." trailer? |
You must indeed always squash your commits. (I have no opinion on the PR itself...) |
@pmetzger Ok, thanks for the info. |
@raimue Friendly ping... any thoughts on this? :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs an fflush(3)
to work correctly, and while at it please sprinkle some error handling in, then it's good to go.
src/pextlib1.0/readline.c
Outdated
hist_file = fopen(s, "a"); | ||
|
||
flock(fileno(hist_file), LOCK_EX); | ||
fprintf(hist_file, "%s\n", current_history()->line); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless hist_file
is a terminal or stderr
, this fprintf(3)
call will be buffered, which means it will not actually trigger writing to disk, rendering your locking moot against modification across multiple instances of macports writing at the same time.
You must either switch hist_file
to line buffering mode using setvbuf(3)
, or call fflush(3)
after writing the line and before returning the lock. I'd probably just call fflush(3)
, it's simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@neverpanic Ok, I went ahead and took your advice for fflush
. Strangely, what you're saying makes perfect sense, but when I tested this out, the locking mechanism actually worked. It was as though it didn't need a flush. I tested it by opening two separate terminals and entering commands into them via CloneKeys. I'm curious now; do you know why that may have happened?
src/pextlib1.0/readline.c
Outdated
} | ||
s = Tcl_GetString(objv[2]); | ||
|
||
hist_file = fopen(s, "a"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add error handling to the fopen(3)
call here? mkdtemp.c
has an example on how to do this, e.g.
if (NULL == (hist_file = fopen(s, "a"))) {
Tcl_AppendResult(interp, "fopen(", s, "): ", strerror(errno), NULL);
return TCL_ERROR;
}
src/pextlib1.0/readline.c
Outdated
return TCL_ERROR; | ||
} | ||
s = Tcl_GetString(objv[2]); | ||
hist_file = fopen(s, "a"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you GitHub review for hiding my review comment against the version in one of the lower commits. Please add error handling here. See mkdtemp.c
for good examples. E.g., use:
if (NULL == (hist_file = fopen(s, "a"))) {
Tcl_AppendResult(interp, "fopen(", s, "): ", strerror(errno), NULL);
return TCL_ERROR;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@neverpanic Thanks for the code, I went ahead and pasted it in verbatim :)
I also added some error-checking for the fprintf
call; please let me know if it's okay. It's not as pretty as the code in mktemp.c
, but it should do the trick.
@neverpanic I went ahead and implemented your changes as you requested. Please let me know if they're satisfactory. I also added some comments for visual and conceptual clarity since I stared at this code without comments and it felt like my eyes were getting poked with curly-braced needles :) |
Thanks! |
@neverpanic You're welcome! Thanks for merging it and for the help! Did you see my comment from last night wherein I had a question about the flushing seeming unnecessary? I'm curious to know what may have been going on... :) |
I think what you were seeing is that the It may just be very hard to hit the race condition that would make the problem visible (and even if two writes were happening at the same time outside of the lock, they may still end up being a single |
@neverpanic Thanks so much for the explanation! This makes more sense to me now. I suspected that Yes, such a situation would indeed make it hard to expose the problem. That is a very hard-to-hit race condition, although possible. And as you also said, if the two writes were mixed into the same syscall then there would be no conflict anyway. Maybe I'll try that test you mention someday, just for fun :D |
As per the discussion here. Please let me know if you have any improvements in mind. Pinging @raimue since we spoke about this together on the aforementioned Trac ticket.