1/* Implement tasking-related runtime actions for CHILL.
2   Copyright (C) 1992,1993 Free Software Foundation, Inc.
3   Author: Wilfried Moser
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING.  If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA.  */
21
22/* As a special exception, if you link this library with other files,
23   some of which are compiled with GCC, to produce an executable,
24   this library does not by itself cause the resulting executable
25   to be covered by the GNU General Public License.
26   This exception does not however invalidate any other reasons why
27   the executable file might be covered by the GNU General Public License.  */
28
29#include "rtltypes.h"
30#include "rts.h"
31
32EXCEPTION (sendfail);
33
34extern void __cause_ex1 (char *ex, char *file, int lineno);
35
36#define CAUSE_SENDFAIL  __cause_ex1 ("sendfail", filename, lineno)
37
38/*
39 * function __send_buffer
40 *
41 * parameters:
42 *     buffer     pointer to buffer descriptor
43 *     data       pointer to data descriptor
44 *     prio       priority for send action
45 *     timeout	  pointer to timeout value
46 *     filename   source file name where function gets called
47 *     lineno     linenumber in source file
48 *
49 * returns:
50 *     int	  0 .. success
51 *                1 .. timeout
52 *
53 * exceptions:
54 *     sendfail
55 *
56 * abstract:
57 *     implement the CHILL SEND buffer action.
58 */
59
60int
61__send_buffer (buffer, data, prio, timeout, filename, lineno)
62     Buffer_Descr    *buffer;
63     Data_Descr      *data;
64     int              prio;
65     void            *timeout;
66     char            *filename;
67     int              lineno;
68{
69  Buffer_Queue        *bq;
70  Buffer_Send_Queue   *bsq, *bsq_entry, *prev_bsq_entry;
71  int                  cnt = 0;
72  int		       retval = 0;
73
74  /* if we don't have anything queued on that buffer,
75     set up the structure */
76  memcpy (&bq, buffer->buf, sizeof (Buffer_Queue *));
77  if (bq == 0)
78    {
79      MALLOC (bq, sizeof (Buffer_Queue));
80      memset (bq, 0, sizeof (Buffer_Queue));
81      memcpy (buffer->buf, &bq, sizeof (Buffer_Queue *));
82    }
83
84  /* look if there is a process delayed on that buffer */
85  if (bq->waitqueue != 0)
86    {
87	Buffer_Wait_Queue	*listentry;
88
89	/* there is already a processes waiting for that buffer,
90	   check datalength and copy the data in */
91	if (bq->waitqueue->datalen < data->length)
92	    CAUSE_SENDFAIL;
93	memcpy (bq->waitqueue->dataptr, data->ptr, data->length);
94
95	/* set up the entry */
96	bq->waitqueue->is_sent = 1;
97	bq->waitqueue->who_sent = THIS;
98
99	/* continue waiting process */
100	__continue_that (bq->waitqueue->this, prio, filename, lineno);
101
102	/* now dequeue all entries of this list */
103	listentry = bq->waitqueue->startlist;
104	while (listentry != 0)
105	{
106	    Buffer_Wait_Queue	*tmp, *prev_entry, *bwq;
107	    Buffer_Queue	*bq;
108
109	    tmp = listentry->chain;
110	    memcpy (&bq, listentry->bufferaddr, sizeof (Buffer_Queue *));
111	    prev_entry = (Buffer_Wait_Queue *)&bq->waitqueue;
112	    bwq = bq->waitqueue;
113
114	    while (bwq != listentry)
115	    {
116		prev_entry = bwq;
117		bwq = bwq->forward;
118	    }
119	    /* dequeue it */
120	    prev_entry->forward = bwq->forward;
121	    bq->waitqueuelength--;
122	    listentry = tmp;
123	}
124
125	/* all done */
126	return 0;
127    }
128
129  /* nothing in waitqueue, set up an entry for sendqueue.
130     Note: we allocate here space for the data too, to reduce
131     calls to malloc and let the dataptr point just behind
132     the Buffer_Send_Queue structure. */
133  MALLOC (bsq_entry, sizeof (Buffer_Send_Queue) + data->length);
134  memset (bsq_entry, 0, sizeof (Buffer_Send_Queue));
135
136  bsq_entry->priority = prio;
137  bsq_entry->this = THIS;
138  bsq_entry->datalen = data->length;
139  bsq_entry->dataptr = bsq_entry + 1;
140  memcpy (bsq_entry->dataptr, data->ptr, data->length);
141
142  /* add entry to sendqueue */
143  prev_bsq_entry = (Buffer_Send_Queue *)&bq->sendqueue;
144  bsq = bq->sendqueue;
145
146  while (bsq != 0 && bsq->priority >= prio)
147    {
148      prev_bsq_entry = bsq;
149      bsq = bsq->forward;
150    }
151  if (bsq == 0)
152    {
153      /* beginning or end of the list */
154      prev_bsq_entry->forward = bsq_entry;
155    }
156  else
157    {
158      /* somewhere in the middle */
159      bsq_entry->forward = prev_bsq_entry->forward;
160      prev_bsq_entry->forward = bsq_entry;
161    }
162
163  if (buffer->maxqueuelength != (unsigned long)-1L &&
164      bq->sendqueuelength >= buffer->maxqueuelength)
165    {
166      /* we have to delay this process */
167      bsq_entry->is_delayed = 1;
168      retval = __delay_this (wait_buffer_send, timeout, filename, lineno);
169      if (retval)
170        {
171	  prev_bsq_entry->forward = bsq_entry->forward;
172	  FREE (bsq_entry);
173        }
174    }
175  else
176    /* just say that there is one more entry in the queue */
177    bq->sendqueuelength++;
178  return retval;
179}
180
181/* force function __print_buffer to be linked */
182extern void __print_buffer ();
183static EntryPoint pev = __print_buffer;
184