resource.c 4.21 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* resource.c
 *
 * External resources associated with a connection, for instance
 * processes and ports. Used to kill or release the resource in
 * question when the connection dies.
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
J.H.M. Dassen's avatar
J.H.M. Dassen committed
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
26
27
28
29
 */

#include "resource.h"

30
#include "gc.h"
Niels Möller's avatar
Niels Möller committed
31
32
33
#include "werror.h"
#include "xalloc.h"

34
35
#include <assert.h>

Niels Möller's avatar
Niels Möller committed
36
/* Prototypes */
37

Niels Möller's avatar
Niels Möller committed
38
39
void dont_free_live_resource(int alive);

40
#define GABA_DEFINE
Niels Möller's avatar
Niels Möller committed
41
#include "resource.h.x"
42
#undef GABA_DEFINE
Niels Möller's avatar
Niels Möller committed
43

44
45
46
47
48
49
50
51
/* Forward declarations */

struct resource_node;

void do_mark_resources(struct resource_node **q,
		       void (*mark)(struct lsh_object *o));

void do_free_resources(struct resource_node **q);
Niels Möller's avatar
Niels Möller committed
52

53
54
55
56
#include "resource.c.x"


/* Sanity check */
57
58
59

/* NOTE: This happens normally during gc_final. Under all other
 * circumstances, it's a serious error. */
60
61
void
dont_free_live_resource(int alive)
Niels Möller's avatar
Niels Möller committed
62
63
{
  if (alive)
64
65
66
67
68
69
70
71
72
73
    {
#if DEBUG_ALLOC
      if (gc_final_p)
	verbose("dont_free_live_resource: "
		"final collection of a live resource!\n");
      else
#endif
	fatal("dont_free_live_resource: "
	      "garbage collecting a live resource!\n");
    }
Niels Möller's avatar
Niels Möller committed
74
75
}

76
77
78
79
80
81
82
/* For resources that are only marked as dead, and taken care of
 * later. */
static void
do_resource_kill(struct resource *self)
{ self->alive = 0; }

void
83
init_resource(struct resource *self,
84
85
86
87
88
89
	      void (*k)(struct resource *))
{
  self->alive = 1;
  self->kill = k ? k : do_resource_kill;
}

90
91
92
93
94
/* The behaviour of a resource list is somewhat similar to
 * a weak list. Nodes that are dead are unlinked automatically,
 * so that they can be garbage collected. */

struct resource_node
Niels Möller's avatar
Niels Möller committed
95
{
96
97
98
99
  struct resource_node *next;
  struct resource *resource;
};

Niels Möller's avatar
Niels Möller committed
100
/* Works as a weak list of resources. */
101
102
103
104
105
106
107
108
109
110
/* GABA:
   (class
     (name concrete_resource_list)
     (super resource_list)
     (vars
       (q indirect-special "struct resource_node *"
                           do_mark_resources do_free_resources)))
*/

/* Loop over the resources, mark the living and unlink the dead. */
111
112
113
void
do_mark_resources(struct resource_node **q,
		  void (*mark)(struct lsh_object *o))
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
{
  struct resource_node *n;
  
  while ( (n = *q) )
    {
      if (n->resource->alive)
	{
	  mark(&n->resource->super);
	  q = &n->next;
	}
      else
	{
	  *q = n->next;
	  lsh_space_free(n);
	}
    }
Niels Möller's avatar
Niels Möller committed
130
131
}

132
/* Free the list. */
133
134
void
do_free_resources(struct resource_node **q)
Niels Möller's avatar
Niels Möller committed
135
{
136
137
138
  struct resource_node *n;

  for (n = *q; n; )
139
    {
140
141
142
143
144
145
146
147
148
149
150
151
152
153
      struct resource_node *old = n;
      n = n->next;
      lsh_space_free(old);
    }
}


static void
do_remember_resource(struct resource_list *s,
		     struct resource *resource)
{
  CAST(concrete_resource_list, self, s);
  struct resource_node *n;

154
155
156
  if (!self->super.super.alive)
    {
      werror("do_remember_resource: resource list is already dead.\n");
157
      KILL_RESOURCE(resource);
158
159
160
      return;
    }
  
161
162
163
164
165
166
167
  NEW_SPACE(n);

  n->resource = resource;
  n->next = self->q;
  self->q = n;
}

168
169
static void
do_kill_all(struct resource *s)
170
171
172
173
174
175
176
{
  CAST(concrete_resource_list, self, s);
  struct resource_node *n;

  for (n = self->q; n; )
    {
      CAST_SUBTYPE(resource, r, n->resource);
Niels Möller's avatar
Niels Möller committed
177
      struct resource_node *old = n;
178

179
      KILL_RESOURCE(r);
180
181
182
      n = n->next;

      lsh_space_free(old);
183
    }
184
185
  self->q = NULL;
  self->super.super.alive = 0;
Niels Möller's avatar
Niels Möller committed
186
187
}
  
188
189
struct resource_list *
empty_resource_list(void)
Niels Möller's avatar
Niels Möller committed
190
{
191
  NEW(concrete_resource_list, self);
192
  init_resource(&self->super.super, do_kill_all);
Niels Möller's avatar
Niels Möller committed
193

194
  trace("empty_resource_list: created %xi\n", self);
195
196
197
  self->super.remember = do_remember_resource;
  
  self->q = NULL;
Niels Möller's avatar
Niels Möller committed
198

199
  return &self->super;
Niels Möller's avatar
Niels Möller committed
200
}