1/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved	by Bram Moolenaar
4 *		 BeBox port Copyright 1997 by Olaf Seibert.
5 *
6 * Do ":help uganda"  in Vim to read copying and usage conditions.
7 * Do ":help credits" in Vim to see a list of people who contributed.
8 * See README.txt for an overview of the Vim source code.
9 */
10/*
11 * os_beos.c  Additional stuff for BeOS (rest is in os_unix.c)
12 */
13
14#include <float.h>
15#include <termios.h>
16#include <kernel/OS.h>
17#include "vim.h"
18
19#if USE_THREAD_FOR_INPUT_WITH_TIMEOUT
20
21#ifdef PROTO	    /* making prototypes on Unix */
22#define sem_id int
23#define thread_id int
24#endif
25
26char_u charbuf;
27signed char charcount;
28sem_id character_present;
29sem_id character_wanted;
30thread_id read_thread_id;
31
32#define TRY_ABORT	0	/* This code does not work so turn it off. */
33
34#if TRY_ABORT
35    static void
36mostly_ignore(int sig)
37{
38}
39#endif
40
41    static long
42read_thread(void *dummy)
43{
44    signal(SIGINT, SIG_IGN);
45    signal(SIGQUIT, SIG_IGN);
46#if TRY_ABORT
47    signal(SIGUSR1, mostly_ignore);
48#endif
49
50    for (;;) {
51	if (acquire_sem(character_wanted) != B_NO_ERROR)
52	    break;
53	charcount = read(read_cmd_fd, &charbuf, 1);
54	release_sem(character_present);
55    }
56
57    return 0;
58}
59
60    void
61beos_cleanup_read_thread(void)
62{
63    if (character_present > 0)
64	delete_sem(character_present);
65    character_present = 0;
66    if (read_thread_id > 0)
67	kill_thread(read_thread_id);
68    read_thread_id = 0;
69}
70
71#endif
72
73/*
74 * select() emulation. Hopefully, in DR9 there will be something
75 * useful supplied by the system. ... Alas, not. Not in AAPR, nor
76 * in PR or even PR2... R3 then maybe? I don't think so!
77 */
78
79    int
80beos_select(int nbits,
81       struct fd_set *rbits,
82       struct fd_set *wbits,
83       struct fd_set *ebits,
84       struct timeval *timeout)
85{
86    bigtime_t tmo;
87
88    if (nbits == 0) {
89	/* select is purely being used for delay */
90	snooze(timeout->tv_sec * 1e6 + timeout->tv_usec);
91	return 0;
92    }
93#if 0
94    /*
95     * This does not seem to work either. Reads here are not supposed to
96     * block indefinitely, yet they do. This is most annoying.
97     */
98    if (FD_ISSET(0, rbits)) {
99	char cbuf[1];
100	int count;
101	struct termios told;
102	struct termios tnew;
103	tcgetattr(0, &told);
104	tnew = told;
105	tnew.c_lflag &= ~ICANON;
106	tnew.c_cc[VMIN] = 0;
107	tnew.c_cc[VTIME] = timeout->tv_sec * 10 + timeout->tv_usec / 100000;
108	tcsetattr(0, TCSANOW, &tnew);
109
110	count = read(0, &cbuf, sizeof(cbuf));
111	tcsetattr(0, TCSANOW, &told);
112	if (count > 0) {
113	    add_to_input_buf(&cbuf[0], count);
114	    return 1;
115	}
116	return 0;
117    }
118#endif
119#if USE_THREAD_FOR_INPUT_WITH_TIMEOUT
120    /*
121     * Check if the operation is really on stdin...
122     */
123    if (FD_ISSET(read_cmd_fd, rbits))
124    {
125	int acquired;
126
127	/*
128	 * Is this the first time through?
129	 * Then start up the thread and initialise the semaphores.
130	 */
131	if (character_present == 0) {
132	    character_present = create_sem(0, "vim character_present");
133	    character_wanted = create_sem(1, "vim character_wanted");
134	    read_thread_id = spawn_thread(read_thread, "vim async read",
135		    B_NORMAL_PRIORITY, NULL);
136	    atexit(beos_cleanup_read_thread);
137	    resume_thread(read_thread_id);
138	}
139
140	/* timeout == NULL means "indefinitely" */
141	if (timeout) {
142	    tmo = timeout->tv_sec * 1e6 + timeout->tv_usec;
143	    /* 0 means "don't wait, which is impossible to do exactly. */
144	    if (tmo == 0)
145		tmo = 1.0;
146	}
147#if TRY_ABORT
148	release_sem(character_wanted);
149#endif
150	if (timeout)
151	    acquired = acquire_sem_etc(character_present, 1, B_TIMEOUT, tmo);
152	else
153	    acquired = acquire_sem(character_present);
154	if (acquired == B_NO_ERROR) {
155	    if (charcount > 0) {
156		add_to_input_buf(&charbuf, 1);
157#if !TRY_ABORT
158		release_sem(character_wanted);
159#endif
160
161		return 1;
162	    } else {
163#if !TRY_ABORT
164		release_sem(character_wanted);
165#endif
166
167		return 0;
168	    }
169	}
170#if TRY_ABORT
171	else {
172	    /*
173	     * Timeout occurred. Break the read() call by sending
174	     * a signal. Problem: it may be just read()ing it now.
175	     * Therefore we still have to finish the handshake with
176	     * the thread and maybe remember the character.
177	     */
178	    kill(read_thread_id, SIGUSR1);
179	    /*
180	     *	If some other error occurred, don't hang now.
181	     * (We will most likely hang later anyway...)
182	     */
183	    if (acquired == B_TIMED_OUT)
184		acquire_sem(character_present);
185	    if (charcount > 0) {
186		add_to_input_buf(&charbuf, 1);
187		return 1;
188	    }
189	    return 0;
190	}
191#endif
192    }
193#endif
194
195    return 0;
196}
197
198