su_port.h 16.2 KB
Newer Older
Pekka Pessi's avatar
Pekka Pessi committed
1 2 3 4 5 6 7
/*
 * This file is part of the Sofia-SIP package
 *
 * Copyright (C) 2005 Nokia Corporation.
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
8
 * This library is free software; you can redistribute it and/or
Pekka Pessi's avatar
Pekka Pessi committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

25 26
#ifndef SU_PORT_H
/** Defined when <su_port.h> has been included. */
Pekka Pessi's avatar
Pekka Pessi committed
27
#define SU_PORT_H
Pekka Pessi's avatar
Pekka Pessi committed
28 29 30 31 32 33 34 35 36 37 38 39

/**@IFILE su_port.h 
 *
 * @brief Internal OS-independent syncronization interface.
 *
 * This looks like the "reactor" pattern.
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
 * 
 * @date Created: Fri May 12 14:13:34 2000 ppessi
 */

40 41 42 43
#ifndef SU_MSG_ARG_T
#define SU_MSG_ARG_T union { char anoymous[4]; }
#endif

Pekka Pessi's avatar
Pekka Pessi committed
44
#ifndef SU_WAIT_H
45
#include "sofia-sip/su_wait.h"
Pekka Pessi's avatar
Pekka Pessi committed
46 47 48
#endif

#ifndef SU_MODULE_DEBUG_H
49
#include "su_module_debug.h"
Pekka Pessi's avatar
Pekka Pessi committed
50 51 52
#endif

#ifndef SU_ALLOC_H
53
#include <sofia-sip/su_alloc.h>
Pekka Pessi's avatar
Pekka Pessi committed
54 55
#endif

56 57
#include <assert.h>

58
#define SU_WAIT_MIN    (16)
Pekka Pessi's avatar
Pekka Pessi committed
59

60
SOFIA_BEGIN_DECLS
Pekka Pessi's avatar
Pekka Pessi committed
61 62 63

/** Message */
struct su_msg_s {
64
  isize_t        sum_size;
Pekka Pessi's avatar
Pekka Pessi committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
  su_msg_t      *sum_next;
  su_task_r      sum_to;
  su_task_r      sum_from;
  su_msg_f       sum_func;
  su_msg_f       sum_report;
  su_msg_arg_t   sum_data[1];		/* minimum size, may be extended */
};

struct _GSource;

/** Root structure */
struct su_root_s {
  int              sur_size;
  su_root_magic_t *sur_magic;
  su_root_deinit_f sur_deinit;
  su_task_r        sur_task;
  su_task_r        sur_parent;
  unsigned         sur_threading : 1;
  unsigned         sur_deiniting : 1;
};

#define SU_ROOT_MAGIC(r) ((r) ? (r)->sur_magic : NULL)

/** Virtual function table for port */
89
typedef struct su_port_vtable {
Pekka Pessi's avatar
Pekka Pessi committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
  unsigned su_vtable_size;
  void (*su_port_lock)(su_port_t *port, char const *who);
  void (*su_port_unlock)(su_port_t *port, char const *who);
  void (*su_port_incref)(su_port_t *port, char const *who);
  void (*su_port_decref)(su_port_t *port, int block, char const *who);
  struct _GSource *(*su_port_gsource)(su_port_t *port);
  int (*su_port_send)(su_port_t *self, su_msg_r rmsg);
  int (*su_port_register)(su_port_t *self,
		       su_root_t *root, 
		       su_wait_t *wait, 
		       su_wakeup_f callback,
		       su_wakeup_arg_t *arg,
		       int priority);
  int (*su_port_unregister)(su_port_t *port,
			    su_root_t *root, 
			    su_wait_t *wait,	
			    su_wakeup_f callback, 
			    su_wakeup_arg_t *arg);
  int (*su_port_deregister)(su_port_t *self, int i);
  int (*su_port_unregister_all)(su_port_t *self,
			     su_root_t *root);
  int (*su_port_eventmask)(su_port_t *self, int index, int socket, int events);
  void (*su_port_run)(su_port_t *self);
  void (*su_port_break)(su_port_t *self);
  su_duration_t (*su_port_step)(su_port_t *self, su_duration_t tout);
  
  int (*su_port_own_thread)(su_port_t const *port);
  
  int (*su_port_add_prepoll)(su_port_t *port,
			     su_root_t *root, 
			     su_prepoll_f *, 
			     su_prepoll_magic_t *);
  
  int (*su_port_remove_prepoll)(su_port_t *port,
				su_root_t *root);

  su_timer_t **(*su_port_timers)(su_port_t *port);

  int (*su_port_multishot)(su_port_t *port, int multishot);

  int (*su_port_threadsafe)(su_port_t *port);
131 132
  /* Extension from > 1.12.0 */
  int (*su_port_yield)(su_port_t *port);
133 134 135
  /* Extension from >= 1.12.4 */
  int (*su_port_wait_events)(su_port_t *port, su_duration_t timeout);
  int (*su_port_getmsgs)(su_port_t *port);
136 137 138 139 140 141 142 143
  /* Extension from >= 1.12.5 */
  int (*su_port_getmsgs_from)(su_port_t *port, su_port_t *cloneport);
  char const *(*su_port_name)(su_port_t const *port);
  int (*su_port_start_shared)(su_root_t *root,
			      su_clone_r return_clone,
			      su_root_magic_t *magic,
			      su_root_init_f init,
			      su_root_deinit_f deinit);
144 145 146 147
  void (*su_port_wait)(su_clone_r rclone);
  int (*su_port_execute)(su_task_r const task,
			 int (*function)(void *), void *arg,
			 int *return_value);  
Pekka Pessi's avatar
Pekka Pessi committed
148 149
} su_port_vtable_t;

Pekka Pessi's avatar
Pekka Pessi committed
150
SOFIAPUBFUN su_port_t *su_port_create(void)
Pekka Pessi's avatar
Pekka Pessi committed
151 152
     __attribute__((__malloc__));

153
/* Extension from >= 1.12.5 */
154 155 156 157 158 159 160 161 162

typedef su_port_t *su_port_create_f(void);
typedef int su_clone_start_f(su_root_t *parent,
			    su_clone_r return_clone,
			    su_root_magic_t *magic,
			    su_root_init_f init,
			    su_root_deinit_f deinit);

SOFIAPUBFUN void su_port_prefer(su_port_create_f *f, su_clone_start_f *);
163 164 165 166 167 168 169 170

SOFIAPUBFUN su_port_t *su_epoll_port_create(void)
     __attribute__((__malloc__));
SOFIAPUBFUN su_port_t *su_poll_port_create(void)
     __attribute__((__malloc__));
SOFIAPUBFUN su_port_t *su_select_port_create(void)
     __attribute__((__malloc__));

171 172 173 174
SOFIAPUBFUN su_clone_start_f su_epoll_clone_start;
SOFIAPUBFUN su_clone_start_f su_poll_clone_start;
SOFIAPUBFUN su_clone_start_f su_select_clone_start;

Pekka Pessi's avatar
Pekka Pessi committed
175 176 177 178
SOFIAPUBFUN void su_msg_delivery_report(su_msg_r msg);
SOFIAPUBFUN su_duration_t su_timer_next_expires(su_timer_t const * t,
						su_time_t now);
SOFIAPUBFUN su_root_t *su_root_create_with_port(su_root_magic_t *magic,
179 180
						su_port_t *port)
  __attribute__((__malloc__));
Pekka Pessi's avatar
Pekka Pessi committed
181

182 183 184 185 186 187 188 189 190 191 192
/* ---------------------------------------------------------------------- */

/* React to multiple events per one poll() to make sure 
 * that high-priority events can never completely mask other events.
 * Enabled by default on all platforms except WIN32 */
#if !defined(WIN32)
#define SU_ENABLE_MULTISHOT_POLL 1
#else
#define SU_ENABLE_MULTISHOT_POLL 0
#endif

193 194
/* ---------------------------------------------------------------------- */
/* Virtual functions */
Pekka Pessi's avatar
Pekka Pessi committed
195

196 197
typedef struct su_virtual_port_s {
  su_home_t        sup_home[1];
Pekka Pessi's avatar
Pekka Pessi committed
198
  su_port_vtable_t const *sup_vtable;
199 200 201 202 203 204 205
} su_virtual_port_t;

static inline
su_home_t *su_port_home(su_port_t const *self)
{
  return (su_home_t *)self;
}
Pekka Pessi's avatar
Pekka Pessi committed
206 207 208 209

static inline
void su_port_lock(su_port_t *self, char const *who)
{
210 211
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base) base->sup_vtable->su_port_lock(self, who);
Pekka Pessi's avatar
Pekka Pessi committed
212 213 214 215 216
}

static inline
void su_port_unlock(su_port_t *self, char const *who)
{
217 218
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base) base->sup_vtable->su_port_unlock(self, who);
Pekka Pessi's avatar
Pekka Pessi committed
219 220 221 222 223
}

static inline
void su_port_incref(su_port_t *self, char const *who)
{
224 225
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base) base->sup_vtable->su_port_incref(self, who);
Pekka Pessi's avatar
Pekka Pessi committed
226 227 228 229 230
}

static inline
void su_port_decref(su_port_t *self, char const *who)
{
231 232
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base) base->sup_vtable->su_port_decref(self, 0, who);
Pekka Pessi's avatar
Pekka Pessi committed
233 234 235 236 237
}

static inline
void su_port_zapref(su_port_t *self, char const *who)
{
238 239
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base) base->sup_vtable->su_port_decref(self, 1, who);
Pekka Pessi's avatar
Pekka Pessi committed
240 241 242 243 244
}

static inline
struct _GSource *su_port_gsource(su_port_t *self)
{
245 246
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  return base ? base->sup_vtable->su_port_gsource(self) : NULL;
Pekka Pessi's avatar
Pekka Pessi committed
247 248 249 250 251
}

static inline
int su_port_send(su_port_t *self, su_msg_r rmsg)
{
252 253 254
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base) 
    return base->sup_vtable->su_port_send(self, rmsg);
Pekka Pessi's avatar
Pekka Pessi committed
255 256 257 258 259 260 261 262 263 264 265 266 267
  errno = EINVAL;
  return -1;
}


static inline
int su_port_register(su_port_t *self,
		     su_root_t *root, 
		     su_wait_t *wait, 
		     su_wakeup_f callback,
		     su_wakeup_arg_t *arg,
		     int priority)
{
268 269 270
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->su_port_register(self, root, wait,
Pekka Pessi's avatar
Pekka Pessi committed
271 272 273 274 275 276 277 278 279 280 281 282
					      callback, arg, priority);
  errno = EINVAL;
  return -1;
}

static inline
int su_port_unregister(su_port_t *self,
		       su_root_t *root, 
		       su_wait_t *wait,	
		       su_wakeup_f callback, 
		       su_wakeup_arg_t *arg)
{
283 284 285
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->
Pekka Pessi's avatar
Pekka Pessi committed
286 287 288 289 290 291 292 293
      su_port_unregister(self, root, wait, callback, arg);
  errno = EINVAL;
  return -1;
}

static inline
int su_port_deregister(su_port_t *self, int i)
{
294 295 296
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->su_port_deregister(self, i);
Pekka Pessi's avatar
Pekka Pessi committed
297 298 299 300 301 302 303 304
  errno = EINVAL;
  return -1;
}

static inline
int su_port_unregister_all(su_port_t *self,
			   su_root_t *root)
{
305 306 307
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->
Pekka Pessi's avatar
Pekka Pessi committed
308 309 310 311 312 313 314 315
      su_port_unregister_all(self, root);
  errno = EINVAL;
  return -1;
}

static inline
int su_port_eventmask(su_port_t *self, int index, int socket, int events)
{
316 317 318
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->
Pekka Pessi's avatar
Pekka Pessi committed
319
      su_port_eventmask(self, index, socket, events);
320
  assert(base);
Pekka Pessi's avatar
Pekka Pessi committed
321 322 323 324 325 326 327
  errno = EINVAL;
  return -1;
}

static inline
void su_port_run(su_port_t *self)
{
328 329 330
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    base->sup_vtable->su_port_run(self);
Pekka Pessi's avatar
Pekka Pessi committed
331 332 333 334 335
}

static inline
void su_port_break(su_port_t *self)
{
336 337 338
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    base->sup_vtable->su_port_break(self);
Pekka Pessi's avatar
Pekka Pessi committed
339 340 341 342 343
}

static inline
su_duration_t su_port_step(su_port_t *self, su_duration_t tout)
{
344 345 346
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->su_port_step(self, tout);
Pekka Pessi's avatar
Pekka Pessi committed
347 348 349 350
  errno = EINVAL;
  return (su_duration_t)-1;
}

351

Pekka Pessi's avatar
Pekka Pessi committed
352 353 354
static inline
int su_port_own_thread(su_port_t const *self)
{
355 356
  su_virtual_port_t const *base = (su_virtual_port_t *)self;
  return base == NULL || base->sup_vtable->su_port_own_thread(self);
Pekka Pessi's avatar
Pekka Pessi committed
357 358 359 360 361 362 363 364
}

static inline
int su_port_add_prepoll(su_port_t *self,
			su_root_t *root, 
			su_prepoll_f *prepoll, 
			su_prepoll_magic_t *magic)
{
365 366 367
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->
Pekka Pessi's avatar
Pekka Pessi committed
368 369 370 371 372 373 374 375 376
      su_port_add_prepoll(self, root, prepoll, magic);
  errno = EINVAL;
  return -1;
}

static inline
int su_port_remove_prepoll(su_port_t *self,
			   su_root_t *root)
{
377 378 379
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->su_port_remove_prepoll(self, root);
Pekka Pessi's avatar
Pekka Pessi committed
380 381 382 383 384 385 386
  errno = EINVAL;
  return -1;
}

static inline
su_timer_t **su_port_timers(su_port_t *self)
{
387 388 389
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->su_port_timers(self);
Pekka Pessi's avatar
Pekka Pessi committed
390 391 392 393 394 395 396
  errno = EINVAL;
  return NULL;
}

static inline
int su_port_multishot(su_port_t *self, int multishot)
{
397 398 399
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->su_port_multishot(self, multishot);
Pekka Pessi's avatar
Pekka Pessi committed
400

401
  assert(base);
Pekka Pessi's avatar
Pekka Pessi committed
402 403 404 405 406 407 408
  errno = EINVAL;
  return -1;
}

static inline
int su_port_threadsafe(su_port_t *self)
{
409 410 411
  su_virtual_port_t *base = (su_virtual_port_t *)self;
  if (base)
    return base->sup_vtable->su_port_threadsafe(self);
Pekka Pessi's avatar
Pekka Pessi committed
412

413
  assert(base);
Pekka Pessi's avatar
Pekka Pessi committed
414 415 416 417
  errno = EINVAL;
  return -1;
}

418 419 420 421 422 423 424 425
static inline
int su_port_getmsgs(su_port_t *self)
{
  su_virtual_port_t *base = (su_virtual_port_t *)self;

  return base->sup_vtable->su_port_getmsgs(self);
}

426 427 428 429 430 431 432 433
static inline
int su_port_getmsgs_from(su_port_t *self, su_port_t *cloneport)
{
  su_virtual_port_t *base = (su_virtual_port_t *)self;

  return base->sup_vtable->su_port_getmsgs_from(self, cloneport);
}

434 435 436 437 438 439
SOFIAPUBFUN void su_port_wait(su_clone_r rclone);

SOFIAPUBFUN int su_port_execute(su_task_r const task,
				int (*function)(void *), void *arg,
				int *return_value);

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
/* ---------------------------------------------------------------------- */

/** Base port object.
 *
 * Port is a per-thread reactor. Multiple root objects executed by a single
 * thread share the su_port_t object.
 */
typedef struct su_base_port_s {
  su_home_t        sup_home[1];
  su_port_vtable_t const *sup_vtable;

  /* Implementation may vary stuff below, too. */
  
  /* Pre-poll callback */
  su_prepoll_f    *sup_prepoll; 
  su_prepoll_magic_t *sup_pp_magic;
  su_root_t       *sup_pp_root;

  /* Message list - this is protected by su_port_lock()/su_port_unlock() */
  su_msg_t        *sup_head, **sup_tail;

  /* Timer list */
  su_timer_t      *sup_timers;

  unsigned         sup_running;	  /**< In su_root_run() loop? */
} su_base_port_t;

/* Base methods */

SOFIAPUBFUN int su_base_port_init(su_port_t *, su_port_vtable_t const *);
SOFIAPUBFUN void su_base_port_deinit(su_port_t *self);

SOFIAPUBFUN void su_base_port_lock(su_port_t *self, char const *who);
SOFIAPUBFUN void su_base_port_unlock(su_port_t *self, char const *who);

SOFIAPUBFUN int su_base_port_own_thread(su_port_t const *self);

SOFIAPUBFUN void su_base_port_incref(su_port_t *self, char const *who);
SOFIAPUBFUN int su_base_port_decref(su_port_t *self,
				    int blocking,
				    char const *who);

SOFIAPUBFUN struct _GSource *su_base_port_gsource(su_port_t *self);

SOFIAPUBFUN su_socket_t su_base_port_mbox(su_port_t *self);
SOFIAPUBFUN int su_base_port_send(su_port_t *self, su_msg_r rmsg);
SOFIAPUBFUN int su_base_port_getmsgs(su_port_t *self);
487 488
SOFIAPUBFUN int su_base_port_getmsgs_from(su_port_t *self,
					   su_port_t *from);
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507

SOFIAPUBFUN void su_base_port_run(su_port_t *self);
SOFIAPUBFUN void su_base_port_break(su_port_t *self);
SOFIAPUBFUN su_duration_t su_base_port_step(su_port_t *self,
					    su_duration_t tout);

SOFIAPUBFUN int su_base_port_add_prepoll(su_port_t *self,
					 su_root_t *root, 
					 su_prepoll_f *, 
					 su_prepoll_magic_t *);

SOFIAPUBFUN int su_base_port_remove_prepoll(su_port_t *self, su_root_t *root);

SOFIAPUBFUN su_timer_t **su_base_port_timers(su_port_t *self);

SOFIAPUBFUN int su_base_port_multishot(su_port_t *self, int multishot);
SOFIAPUBFUN int su_base_port_threadsafe(su_port_t *self);
SOFIAPUBFUN int su_base_port_yield(su_port_t *self);

508 509 510 511 512
SOFIAPUBFUN int su_base_port_start_shared(su_root_t *parent,
					  su_clone_r return_clone,
					  su_root_magic_t *magic,
					  su_root_init_f init,
					  su_root_deinit_f deinit);
513 514
SOFIAPUBFUN void su_base_port_wait(su_clone_r rclone);

515 516 517 518 519 520 521 522 523 524 525
/* ---------------------------------------------------------------------- */

#if SU_HAVE_PTHREADS

#include <pthread.h>

#define SU_MBOX_SIZE 2

/** Pthread port object */ 
typedef struct su_pthread_port_s {
  su_base_port_t   sup_base[1];
526 527
  struct su_pthread_port_waiting_parent 
                  *sup_waiting_parent;
528
  pthread_t        sup_tid;
529 530 531 532 533 534 535
  pthread_mutex_t  sup_runlock[1];
#if 0
  pthread_cond_t   sup_resume[1];
  short            sup_paused;	/**< True if thread is paused */
#endif
  short            sup_thread;	/**< True if thread is active */
  short            sup_mbox_index;
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
  su_socket_t      sup_mbox[SU_MBOX_SIZE];
} su_pthread_port_t;

/* Pthread methods */

SOFIAPUBFUN int su_pthread_port_init(su_port_t *, su_port_vtable_t const *);
SOFIAPUBFUN void su_pthread_port_deinit(su_port_t *self);

SOFIAPUBFUN void su_pthread_port_lock(su_port_t *self, char const *who);
SOFIAPUBFUN void su_pthread_port_unlock(su_port_t *self, char const *who);

SOFIAPUBFUN int su_pthread_port_own_thread(su_port_t const *self);

SOFIAPUBFUN int su_pthread_port_send(su_port_t *self, su_msg_r rmsg);

551
#if 0				/* not yet  */
552
SOFIAPUBFUN su_port_t *su_pthread_port_create(void);
553 554 555 556 557 558 559 560 561 562 563 564 565
SOFIAPUBFUN su_port_t *su_pthread_port_start(su_root_t *parent,
					     su_clone_r return_clone,
					     su_root_magic_t *magic,
					     su_root_init_f init,
					     su_root_deinit_f deinit);
#endif

SOFIAPUBFUN int su_pthreaded_port_start(su_port_create_f *create,
					su_root_t *parent,
					su_clone_r return_clone,
					su_root_magic_t *magic,
					su_root_init_f init,
					su_root_deinit_f deinit);
566 567 568 569 570 571

SOFIAPUBFUN void su_pthread_port_wait(su_clone_r rclone);
SOFIAPUBFUN int su_pthread_port_execute(su_task_r const task,
					int (*function)(void *), void *arg,
					int *return_value);

572

573 574 575 576 577
#if 0
SOFIAPUBFUN int su_pthread_port_pause(su_port_t *self);
SOFIAPUBFUN int su_pthread_port_resume(su_port_t *self);
#endif

578 579 580 581 582 583 584 585 586 587
#else

typedef su_base_port_t su_pthread_port_t;

#define su_pthread_port_init   su_base_port_init
#define su_pthread_port_deinit su_base_port_deinit
#define su_pthread_port_lock   su_base_port_lock
#define su_pthread_port_unlock su_base_port_unlock
#define su_pthread_port_own_thread su_base_port_own_thread
#define su_pthread_port_send   su_base_port_send
588 589
#define su_pthread_port_wait   su_base_port_wait
#define su_pthread_port_execute  su_base_port_execute
Pekka Pessi's avatar
Pekka Pessi committed
590 591 592

#endif

593 594
SOFIA_END_DECLS

Pekka Pessi's avatar
Pekka Pessi committed
595
#endif /* SU_PORT_H */