2
* Copyright © 2012 Keith Packard <keithp@keithp.com>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; version 2 of the License.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
* General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26
extend namespace Client {
27
public namespace Link {
29
public typedef List::list_t + struct {
33
public typedef *message_struct message_t;
35
public exception link_error(string);
42
semaphore replies_sem;
44
semaphore notices_sem;
46
Mutex::mutex command_lock;
47
Mutex::mutex notice_lock;
48
Mutex::mutex reply_lock;
52
public typedef *link_struct link_t;
54
public exception link_closing();
56
void read_replies(link_t l) {
59
message_t m = &(message_struct) { .reply = RR::Lex::recv(l->f) };
60
if (dim(m->reply) == 0)
62
twixt (Mutex::acquire(l->reply_lock); Mutex::release(l->reply_lock)) {
63
if (m->reply[0] == "NOTICE") {
64
List::append(m, &l->notices);
65
Semaphore::signal(l->notices_sem);
67
List::append(m, &l->replies);
68
Semaphore::signal(l->replies_sem);
72
} catch Thread::signal(int sig) {
73
} catch File::io_eof(file f) {
75
} catch File::io_error(string reason, File::error_type error, file f) {
78
while (Semaphore::count(l->notices_sem) < 0)
79
Semaphore::signal(l->notices_sem);
80
while (Semaphore::count(l->replies_sem) < 0)
81
Semaphore::signal(l->replies_sem);
84
public message_t command(link_t l, string format, poly args...) {
86
twixt (Mutex::acquire(l->command_lock); Mutex::release(l->command_lock)) {
88
RR::Send::send(l->f, format, args...);
90
} catch File::io_error(string reason, File::error_type error, file f) {
91
raise link_error(sprintf("I/O error on link: %s", reason));
93
Semaphore::wait(l->replies_sem);
94
twixt(Mutex::acquire(l->reply_lock); Mutex::release(l->reply_lock)) {
97
reply = List::first(&l->replies);
104
public message_t notice(link_t l) {
106
twixt (Mutex::acquire(l->notice_lock); Mutex::release(l->notice_lock)) {
107
Semaphore::wait(l->notices_sem);
108
twixt(Mutex::acquire(l->reply_lock); Mutex::release(l->reply_lock)) {
110
raise link_closing();
111
notice = List::first(&l->notices);
112
List::remove(notice);
118
public link_t new (string host, int port) {
119
link_t l = &(link_struct) {
123
.command_lock = Mutex::new(),
124
.notice_lock = Mutex::new(),
125
.reply_lock = Mutex::new(),
126
.replies_sem = Semaphore::new(),
127
.notices_sem = Semaphore::new(),
130
List::init(&l->replies);
131
List::init(&l->notices);
133
l->f = Net::connect (l->host, l->port);
134
l->reader = fork read_replies(l);
138
public void close(link_t l) {
140
Thread::send_signal(l->reader, 1);
141
Thread::join(l->reader);