Hi all, first time poster to this list, hope that this is right
list to post to...
I've adapted some code to my own uses (shown below) but have run
into an odd problem, and I'm hoping that someone can explain what
is going on to me. As a part of my open_TTY_OSX() function, I
call ioctl(context->fileDescriptor, TIOCEXCL), which prevents any
non-root program from opening the same device. Now this is where
it gets odd for me. I am testing all this code using some unit
tests that I wrote. The unit tests call open_TTY_OSX() and then
balance the call with a call to close_TTY_OSX() on the same file
descriptor. Originally, I did NOT have the ioctl(context-
>fileDescriptor, TIOCNXCL) call in close_TTY_OSX(), and the result
was that if I tried to open the same device again, it would fail
with EBUSY. So basically:
open_TTY_OSX("/dev/ttyp1", foo) // no problem
close_TTY_OSX(foo) // no problem
open_TTY_OSX("/dev/ttyp1, bar) // Fails with EBUSY
Well, I figured that this isn't that big a deal, I just let my
process exit nicely, and the restart the debugging session,
right? No good. The only way for me to make things play nice is
to quit XCode, and even that doesn't seem to work 100% of the
time. My question is why? When I close, I reset the attributes,
and I close() the descriptor. That should make the blocking part
go away, right? What am I doing wrong?
Oh, note that adjAssert() is a macro like assert(); I just hacked
in some extra stuff that I needed, and didn't want the names
conflicting.
Thanks for any help,
Cem Karan
#define ERROR_CLOSE_FD_TTY_OSX_PRIVATE
(FD) \
{
\
struct stat
myStat; \
perror
(NULL); \
fflush
(stderr); \
fflush
(stdout); \
if (FD !=
-1) \
{
\
printf("Closing file
descriptor"); \
fstat(FD,
&myStat); \
close
(FD); \
}
\
}
boolean_t open_TTY_OSX(char *devicePath, OSX_TTYcontext context)
{
size_t counter;
adjAssert((devicePath != NULL) && (context != NULL));
if ((devicePath == NULL) || (context == NULL))
return false;
context->fileDescriptor = open(devicePath, O_RDWR | O_NOCTTY |
O_NONBLOCK);
if (context->fileDescriptor == -1){
ERROR_CLOSE_FD_TTY_OSX_PRIVATE(context->fileDescriptor);
return false;
}
if (tcgetattr(context->fileDescriptor, &(context->original))
== -1) {
printf("Error getting tty attributes %s - %s(%d).\n",
devicePath, strerror(errno), errno);
ERROR_CLOSE_FD_TTY_OSX_PRIVATE(context->fileDescriptor);
return false;
}
memcpy(&(context->current), &(context->original), sizeof
(struct termios));
if (ioctl(context->fileDescriptor, TIOCEXCL) == -1) {
ERROR_CLOSE_FD_TTY_OSX_PRIVATE(context->fileDescriptor);
return false;
}
if (fcntl(context->fileDescriptor, F_SETFL, 0) == -1) {
ERROR_CLOSE_FD_TTY_OSX_PRIVATE(context->fileDescriptor);
return false;
}
if (fcntl(context->fileDescriptor, F_NOCACHE, 1) == -1) {
ERROR_CLOSE_FD_TTY_OSX_PRIVATE(context->fileDescriptor);
return false;
}
for (counter = 0; counter < NCCS; counter++)
(context->current).c_cc[counter] = _POSIX_VDISABLE;
cfmakeraw(&(context->current));
(context->current).c_cc[VMIN] = 1;
(context->current).c_cc[VTIME] = 1;
cfsetspeed(&(context->current), B57600); /* Set 57600 baud */
(context->current).c_cflag |= (CS8 | CREAD | CLOCAL);
if (tcsetattr(context->fileDescriptor, TCSANOW, &(context-
>current)) == -1) {
ERROR_CLOSE_FD_TTY_OSX_PRIVATE(context->fileDescriptor);
return false;
}
return true;
}
void close_TTY_OSX(OSX_TTYcontext context)
{
int result;
adjAssert(context != NULL);
if (tcdrain(context->fileDescriptor) == -1) {
printf("Error waiting for drain - %s(%d).\n",
strerror(errno), errno);
}
if (ioctl(context->fileDescriptor, TIOCNXCL) == -1) {
ERROR_CLOSE_FD_TTY_OSX_PRIVATE(context->fileDescriptor);
}
if (tcsetattr(context->fileDescriptor, TCSANOW, &(context-
>original)) == -1) {
printf("Error resetting tty attributes - %s(%d).\n",
strerror(errno), errno);
}
result = close(context->fileDescriptor);
if (result != 0)
perror(NULL);
}