Instead of using a parallel port, do you think you are using a serial device? Since you have a TTL signal, you may need a level converter to convert TTL to RS232 +/- 12V levels. After using the serial device, you can use standard ioctl() serial calls to detect a change in the state of the control signal.
In particular, you can use TIOCMIWAIT ioctl on a connected serial device to wait for a change, for example, of a DCD line that you would connect to a clock source.
Your user space application will be blocked waiting for the TIOCMIWAIT ioctl system call until the state on your watch line changes, after which your application becomes executable and returns from ioctl. You may need to make sure that you deal with a situation where you receive a state interrupt change on both the rising and falling edges of your serial control signals. On some UART devices (for example, TL16C554A UART), it is possible that you only get an interrupt for a signal to go in one direction. For example, for the TL16C554A, TIOCMIWAIT will only leak to the leading edge of any change in the Ring Indicate signal.
Using serial ioctls in this way also has the advantage that you can use a USB-Serial dongle that supports TIOCMIWAIT if required (for example, PL2303) and still maintain user-level software compatibility, albeit at the expense of increased latency due to USB.
If you need lower latency than can be achieved with user space, it is best to write a kernel driver module that can handle synchronization and sampling, but I would not suggest this route if it is absolutely necessary. Easier to develop user space code.
Here are some partial examples of C code snippets for using TIOCMIWAIT ioctl.
int serial_fd = open(cmdline.device_name, O_RDWR | O_NONBLOCK | O_NOCTTY); static const unsigned int ri_flag = TIOCM_RNG; while (1) { if (ioctl(serial_fd, TIOCMIWAIT, ri_flag)) { fprintf(stderr, "ioctl() failed waiting for RI edge [%s]\n", strerror(errno)); break; } }