haiku/headers/os/drivers/tty/tty_module.h
Adrien Destugues 0f6f5adb50 generic/tty: restore lock sharing between master and slave TTYs
The code in this module was derived from the one in driver/tty. However,
the driver uses a shared lock between the master and slave side of a
TTY, and this was changed to use two separate locks. The approach with
two locks does not work. It seems the change was unfinished and the
second TTY was never locked. But attempting to lock it will result in
lock inversion problems, unless we do complicated things (try to find
which of the two TTY is the master side, and lock that first, for
example). It is simpler to restore the shared lock as used in the
driver.

To set up the shared lock, I modified the tty_create function to take a
pointer to the master TTY when creating the slave. Maybe it makes more
sense to create both sides in the same call, create_tty_pair?

However, this does not work as easily as I wanted, because there is some
recursion going on: at least in one case, the tty_control function is
calling the driver's tty_service function, which in turns attempts to
call back into tty_control for the "other side" TTY. To handle this
case, replace the mutex with a recursive_lock.

Fixes #17091, where the root problem was access to
other_tty->select_pool without locking. This was also made unconvenient
to debug because select_pool objects are self-deleting, when the last
item in the pool is removed. As a result, the code accessing it without
log would suddenly find out that the data it was accessing had been
freed and erased.

This also makes the TTY code in driver/tty and generic/tty a bit more
similar than it was before, and brings us one step closer to merging the
two together. There are still two main differences and I don't know
enough about TTY to decide if they are important, and which version
should be kept:
- The driver has extra code for "background" read and write. I don't
  know what this is used for.
- The driver has a single "settings" instance shared by a master and
  slave TTY, while the module has two separate instances, but seems to
  copy one to the other. I'm not sure which approach is correct.

Change-Id: Ie2daddd027859ce32ba395af76b4f109f8b984b0
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4604
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
2021-10-21 14:49:15 +00:00

76 lines
2.1 KiB
C

/*
* Copyright 2010, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _TTY_MODULE_H
#define _TTY_MODULE_H
#include <module.h>
#include <termios.h>
#include <Select.h>
struct tty;
struct tty_cookie;
typedef bool (*tty_service_func)(struct tty *tty, uint32 op, void *buffer,
size_t length);
// flags
#define TTYCARRIER (1 << 0)
#define TTYWRITABLE (1 << 1)
#define TTYWRITING (1 << 2)
#define TTYREADING (1 << 3)
#define TTYOSTOPPED (1 << 4)
#define TTYEXCLUSIVE (1 << 5)
#define TTYHWDCD (1 << 6)
#define TTYHWCTS (1 << 7)
#define TTYHWDSR (1 << 8)
#define TTYHWRI (1 << 9)
#define TTYFLOWFORCED (1 << 10)
// ops
#define TTYENABLE 0 /* bool enabled */
#define TTYSETMODES 1 /* struct termios termios */
#define TTYOSTART 2
#define TTYOSYNC 3
#define TTYISTOP 4 /* bool stopInput */
#define TTYSETBREAK 5 /* bool break */
#define TTYSETDTR 6 /* bool dataTerminalReady */
#define TTYSETRTS 7 /* bool requestToSend */
#define TTYGETSIGNALS 8 /* call tty_hardware_signal for all bits */
#define TTYFLUSH 9 /* clear input and/or output buffers */
typedef struct tty_module_info tty_module_info;
struct tty_module_info {
module_info mi;
struct tty *(*tty_create)(tty_service_func serviceFunction, struct tty* master);
void (*tty_destroy)(struct tty *tty);
struct tty_cookie *
(*tty_create_cookie)(struct tty *masterTTY, struct tty *slaveTTY,
uint32 openMode);
void (*tty_close_cookie)(struct tty_cookie *cookie);
void (*tty_destroy_cookie)(struct tty_cookie *cookie);
status_t (*tty_read)(struct tty_cookie *cookie, void *_buffer,
size_t *_length);
status_t (*tty_write)(struct tty_cookie *cookie, const void *buffer,
size_t *length);
status_t (*tty_control)(struct tty_cookie *cookie, uint32 op,
void *buffer, size_t length);
status_t (*tty_select)(struct tty_cookie *cookie, uint8 event,
uint32 ref, selectsync *sync);
status_t (*tty_deselect)(struct tty_cookie *cookie, uint8 event,
selectsync *sync);
status_t (*tty_hardware_signal)(struct tty_cookie *cookie,
int signal, bool);
};
#define B_TTY_MODULE_NAME "generic/tty/v1"
#endif /* _TTY_MODULE_H */