2 * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * LATCHESAR IONKOV AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
31 extern int printfcall(FILE *f
, Npfcall
*fc
, int dotu
);
33 static Npfcall
*np_conn_new_incall(Npconn
*conn
);
34 static void np_conn_free_incall(Npconn
*, Npfcall
*, int);
35 static void *np_conn_read_proc(void *);
38 np_conn_create(Npsrv
*srv
, Nptrans
*trans
)
42 conn
= malloc(sizeof(*conn
));
46 //fprintf(stderr, "np_conn_create %p\n", conn);
47 pthread_mutex_init(&conn
->lock
, NULL
);
48 pthread_mutex_init(&conn
->wlock
, NULL
);
49 pthread_cond_init(&conn
->resetcond
, NULL
);
50 pthread_cond_init(&conn
->resetdonecond
, NULL
);
54 conn
->msize
= srv
->msize
;
55 conn
->dotu
= srv
->dotu
;
57 conn
->fidpool
= np_fidpool_create();
61 conn
->freerclist
= NULL
;
62 np_srv_add_conn(srv
, conn
);
64 pthread_create(&conn
->rthread
, NULL
, np_conn_read_proc
, conn
);
69 np_conn_incref(Npconn
*conn
)
71 pthread_mutex_lock(&conn
->lock
);
73 pthread_mutex_unlock(&conn
->lock
);
77 np_conn_decref(Npconn
*conn
)
81 pthread_mutex_lock(&conn
->lock
);
82 assert(conn
->refcount
> 0);
85 pthread_mutex_unlock(&conn
->lock
);
90 np_fidpool_destroy(conn
->fidpool
);
94 fc
= conn
->freerclist
;
95 conn
->freerclist
= NULL
;
102 pthread_mutex_unlock(&conn
->lock
);
103 pthread_mutex_destroy(&conn
->lock
);
104 pthread_cond_destroy(&conn
->resetcond
);
105 pthread_cond_destroy(&conn
->resetdonecond
);
110 np_conn_read_proc(void *a
)
112 int i
, n
, size
, msize
;
119 pthread_detach(pthread_self());
121 np_conn_incref(conn
);
124 fc
= np_conn_new_incall(conn
);
126 while (conn
->trans
&& (i
= np_trans_read(conn
->trans
, fc
->pkt
+ n
, msize
- n
)) > 0) {
127 pthread_mutex_lock(&conn
->lock
);
128 if (conn
->resetting
) {
129 pthread_cond_wait(&conn
->resetdonecond
, &conn
->lock
);
130 n
= 0; /* discard all input */
133 pthread_mutex_unlock(&conn
->lock
);
140 size
= fc
->pkt
[0] | (fc
->pkt
[1]<<8) | (fc
->pkt
[2]<<16) | (fc
->pkt
[3]<<24);
144 if (!np_deserialize(fc
, fc
->pkt
, conn
->dotu
))
147 if (conn
->srv
->debuglevel
) {
148 fprintf(stderr
, "<<< (%p) ", conn
);
149 np_printfcall(stderr
, fc
, conn
->dotu
);
150 fprintf(stderr
, "\n");
153 fc1
= np_conn_new_incall(conn
);
155 memmove(fc1
->pkt
, fc
->pkt
+ size
, n
- size
);
158 req
= np_req_alloc(conn
, fc
);
159 pthread_mutex_lock(&srv
->lock
);
160 if (!conn
->resetting
)
161 np_srv_add_req(srv
, req
);
164 pthread_mutex_unlock(&srv
->lock
);
171 pthread_mutex_lock(&conn
->lock
);
174 np_conn_free_incall(conn
, fc
, 0);
175 pthread_mutex_unlock(&conn
->lock
);
177 np_srv_remove_conn(conn
->srv
, conn
);
178 np_conn_reset(conn
, 0, 0);
181 np_trans_destroy(trans
);
183 np_conn_decref(conn
);
188 np_conn_reset(Npconn
*conn
, u32 msize
, int dotu
)
192 Npreq
*req
, *req1
, *preqs
, **reqs
;
195 pthread_mutex_lock(&conn
->lock
);
197 pthread_mutex_unlock(&conn
->lock
);
199 pthread_mutex_lock(&conn
->srv
->lock
);
201 // first flush all outstanding requests
203 req
= srv
->reqs_first
;
204 while (req
!= NULL
) {
206 if (req
->conn
== conn
) {
207 np_srv_remove_req(srv
, req
);
214 // then flush all working requests
216 req
= conn
->srv
->workreqs
;
217 while (req
!= NULL
) {
218 if (req
->conn
== conn
&& (msize
==0 || req
->tcall
->type
!= Tversion
))
224 reqs
= malloc(n
* sizeof(Npreq
*));
226 req
= conn
->srv
->workreqs
;
227 while (req
!= NULL
) {
228 if (req
->conn
== conn
&& (msize
==0 || req
->tcall
->type
!= Tversion
))
229 reqs
[n
++] = np_req_ref(req
);
232 pthread_mutex_unlock(&conn
->srv
->lock
);
235 while (req
!= NULL
) {
237 np_conn_respond(req
);
242 for(i
= 0; i
< n
; i
++) {
244 if (req
->conn
->srv
->flush
)
245 (*req
->conn
->srv
->flush
)(req
);
248 /* wait until all working requests finish */
250 pthread_mutex_lock(&conn->lock);
252 for(i = 0; i < n; i++)
253 if (!reqs[i]->responded)
259 pthread_cond_wait(&conn->resetcond, &conn->lock);
262 pthread_mutex_lock(&srv
->lock
);
264 for(req
= srv
->workreqs
; req
!= NULL
; req
= req
->next
)
265 if (req
->conn
== conn
&& (msize
==0 || req
->tcall
->type
!= Tversion
))
271 pthread_cond_wait(&conn
->resetcond
, &srv
->lock
);
273 pthread_mutex_unlock(&srv
->lock
);
275 /* free old pool of fcalls */
276 fc
= conn
->freerclist
;
277 conn
->freerclist
= NULL
;
285 np_fidpool_destroy(conn
->fidpool
);
286 conn
->fidpool
= NULL
;
292 conn
->fidpool
= np_fidpool_create();
293 pthread_cond_broadcast(&conn
->resetdonecond
);
296 pthread_mutex_unlock(&conn
->lock
);
298 /* free the working requests */
299 for(i
= 0; i
< n
; i
++)
300 np_req_unref(reqs
[i
]);
305 np_conn_shutdown(Npconn
*conn
)
309 pthread_mutex_lock(&conn
->lock
);
312 pthread_mutex_unlock(&conn
->lock
);
315 np_trans_destroy(trans
);
319 np_conn_respond(Npreq
*req
)
332 pthread_mutex_lock(&conn
->lock
);
333 send
= conn
->trans
&& !conn
->resetting
;
334 pthread_mutex_unlock(&conn
->lock
);
337 pthread_mutex_lock(&conn
->wlock
);
338 if (conn
->srv
->debuglevel
) {
339 fprintf(stderr
, ">>> (%p) ", conn
);
340 np_printfcall(stderr
, rc
, conn
->dotu
);
341 fprintf(stderr
, "\n");
343 n
= np_trans_write(conn
->trans
, rc
->pkt
, rc
->size
);
344 pthread_mutex_unlock(&conn
->wlock
);
347 pthread_mutex_lock(&conn
->lock
);
350 pthread_mutex_unlock(&conn
->lock
);
355 np_conn_free_incall(req
->conn
, req
->tcall
, 1);
360 if (conn
->resetting
) {
361 pthread_mutex_lock(&conn
->srv
->lock
);
362 pthread_cond_broadcast(&conn
->resetcond
);
363 pthread_mutex_unlock(&conn
->srv
->lock
);
367 np_trans_destroy(trans
); /* np_conn_read_proc will take care of resetting */
371 np_conn_new_incall(Npconn
*conn
)
375 pthread_mutex_lock(&conn
->lock
);
376 // if (!conn->trans) {
377 // pthread_mutex_unlock(&conn->lock);
381 if (conn
->freerclist
) {
382 fc
= conn
->freerclist
;
383 conn
->freerclist
= fc
->next
;
386 fc
= malloc(sizeof(*fc
) + conn
->msize
);
390 pthread_mutex_unlock(&conn
->lock
);
394 fc
->pkt
= (u8
*) fc
+ sizeof(*fc
);
395 pthread_mutex_unlock(&conn
->lock
);
401 np_conn_free_incall(Npconn
* conn
, Npfcall
*rc
, int lock
)
407 pthread_mutex_lock(&conn
->lock
);
409 if (conn
->freercnum
< 64) {
410 rc
->next
= conn
->freerclist
;
411 conn
->freerclist
= rc
;
416 pthread_mutex_unlock(&conn
->lock
);