1 |
/* ??? ports |
/* Communication ports. |
2 |
Copyright 1999, 2000, 2001, 2002 Johan Rydberg, jrydberg@rtmk.org. |
Copyright 1999, 2000, 2001, 2002 Johan Rydberg, jrydberg@rtmk.org. |
3 |
|
|
4 |
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
30 |
static struct ipc_port *port_template; |
static struct ipc_port *port_template; |
31 |
|
|
32 |
/* Initialize ports. */ |
/* Initialize ports. */ |
|
|
|
33 |
void |
void |
34 |
ipc_port_init (void) |
ipc_port_init (void) |
35 |
{ |
{ |
44 |
|
|
45 |
port_template->ref_count = 1; |
port_template->ref_count = 1; |
46 |
port_template->active_p = true; |
port_template->active_p = true; |
47 |
|
port_template->pset = 0; |
48 |
|
|
49 |
/* ??? can we initialize the thread lock here? */ |
/* ??? can we initialize the thread lock here? */ |
50 |
} |
} |
52 |
|
|
53 |
/* Create a new IPC port. The port is return in PORTP. |
/* Create a new IPC port. The port is return in PORTP. |
54 |
Returns standard kernel return code. */ |
Returns standard kernel return code. */ |
|
|
|
55 |
kern_return_t |
kern_return_t |
56 |
ipc_port_create (struct ipc_port **portp) |
ipc_port_create (struct ipc_port **portp) |
57 |
{ |
{ |
63 |
|
|
64 |
*port = *port_template; |
*port = *port_template; |
65 |
|
|
66 |
|
queue_init (&port->pset_members); |
67 |
thread_lock_init (&port->lock, true, true); |
thread_lock_init (&port->lock, true, true); |
68 |
ipc_tqueue_init (&port->waiting_threads); |
ipc_tqueue_init (&port->waiting_threads); |
69 |
ipc_tqueue_init (&port->blocked_threads); |
ipc_tqueue_init (&port->blocked_threads); |
85 |
} |
} |
86 |
|
|
87 |
/* Allocate a new port. Receive rights are returned in PORTP. */ |
/* Allocate a new port. Receive rights are returned in PORTP. */ |
|
|
|
88 |
kern_return_t |
kern_return_t |
89 |
port_allocate (struct task *task, rtmk_port_t *portp) |
port_allocate (struct task *task, rtmk_port_t *portp) |
90 |
{ |
{ |
92 |
return ipc_port_create ((struct ipc_port **) portp); |
return ipc_port_create ((struct ipc_port **) portp); |
93 |
} |
} |
94 |
|
|
95 |
|
/* Allocate a new named port. We fail if name already exits. */ |
96 |
kern_return_t |
kern_return_t |
97 |
port_allocate_name (struct task *task, rtmk_port_t name) |
port_allocate_name (struct task *task, rtmk_port_t name) |
98 |
{ |
{ |
111 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
112 |
} |
} |
113 |
|
|
114 |
|
/* Allocate a new port set. When created the port set does not |
115 |
|
contain any members. Return receive rights in PSETP. */ |
116 |
|
kern_return_t |
117 |
|
port_set_allocate (struct task *task, rtmk_port_t *psetp) |
118 |
|
{ |
119 |
|
struct ipc_port *pset; |
120 |
|
kern_return_t kr; |
121 |
|
|
122 |
|
kr = ipc_port_create (& pset); |
123 |
|
if (kr) |
124 |
|
return kr; |
125 |
|
pset->is_pset_p = 1; |
126 |
|
*psetp = (rtmk_port_t) pset; |
127 |
|
return 0; |
128 |
|
} |
129 |
|
|
130 |
|
/* Insert PORT into PORT_SET. If PORT_SET is NULL, we remove |
131 |
|
PORT from the port set it currently belongs to. */ |
132 |
|
kern_return_t |
133 |
|
port_move_member (struct task *task, struct ipc_port *port, |
134 |
|
struct ipc_port *pset) |
135 |
|
{ |
136 |
|
if (! port) |
137 |
|
return KERN_INVALID_ARGUMENT; |
138 |
|
|
139 |
|
if (pset) |
140 |
|
{ |
141 |
|
if (! pset->is_pset_p) |
142 |
|
return KERN_INVALID_ARGUMENT; |
143 |
|
|
144 |
|
/* If port is already a member of a port set we |
145 |
|
remove the port from it and insert into new. */ |
146 |
|
if (port->pset) |
147 |
|
{ |
148 |
|
queue_remove (&port->pset->pset_members, port, |
149 |
|
struct ipc_port *, link); |
150 |
|
port->pset = 0; |
151 |
|
} |
152 |
|
|
153 |
|
queue_enter (& pset->pset_members, port, struct ipc_port *, link); |
154 |
|
port->pset = pset; |
155 |
|
} |
156 |
|
else |
157 |
|
{ |
158 |
|
if (! port->pset) |
159 |
|
return KERN_INVALID_ARGUMENT; |
160 |
|
|
161 |
|
queue_remove (&port->pset->pset_members, port, |
162 |
|
struct ipc_port *, link); |
163 |
|
port->pset = 0; |
164 |
|
} |
165 |
|
return KERN_SUCCESS; |
166 |
|
} |
167 |
|
|
168 |
/* Inserts into TASK the caller's right for PORT. RIGHT_NAME is name in |
/* Inserts into TASK the caller's right for PORT. RIGHT_NAME is name in |
169 |
TASK's IPC object. RIGHT_TYPE specifies right type. */ |
TASK's IPC object. RIGHT_TYPE specifies right type. */ |
170 |
kern_return_t |
kern_return_t |
171 |
port_insert_right (struct task *task, struct ipc_port *port, |
port_insert_right (struct task *task, struct ipc_port *port, |
172 |
rtmk_port_name_t right_name, rtmk_port_type_t right_type) |
rtmk_port_name_t right_name, rtmk_port_type_t right_type) |
173 |
{ |
{ |
174 |
/* ??? lock object. */ |
kern_return_t kr; |
175 |
return |
|
176 |
ipc_object_insert (task->ipc_object, port, right_type, right_name); |
ipc_object_lock (task->ipc_object); |
177 |
/* ??? unlock object. */ |
kr = ipc_object_insert (task->ipc_object, port, right_type, right_name); |
178 |
|
ipc_object_unlock (task->ipc_object); |
179 |
|
return kr; |
180 |
|
} |
181 |
|
|
182 |
|
/* Removes TASK's rights for NAME. The name becomes immediately |
183 |
|
available for reuse. */ |
184 |
|
kern_return_t |
185 |
|
port_destroy (struct task *task, rtmk_port_name_t name) |
186 |
|
{ |
187 |
|
struct ipc_entry *entry; |
188 |
|
kern_return_t kr; |
189 |
|
|
190 |
|
ipc_object_lock (task->ipc_object); |
191 |
|
kr = ipc_object_remove (task->ipc_object, &entry, name); |
192 |
|
if (! kr) |
193 |
|
{ |
194 |
|
ipc_object_unlock (task->ipc_object); |
195 |
|
return kr; |
196 |
|
} |
197 |
|
assert (entry && entry->ie_port); |
198 |
|
entry->ie_port->active_p = 0; |
199 |
|
ipc_object_unlock (task->ipc_object); |
200 |
|
|
201 |
|
kmem_cache_free (ipc_entry_cache, entry); |
202 |
|
return KERN_SUCCESS; |
203 |
|
} |
204 |
|
|
205 |
|
/* Syscall version of function above. */ |
206 |
|
struct port_destroy_args |
207 |
|
{ |
208 |
|
rtmk_port_t task_name; |
209 |
|
rtmk_port_name_t name; |
210 |
|
}; |
211 |
|
|
212 |
|
kern_return_t |
213 |
|
syscall_port_destroy (struct port_destroy_args *a) |
214 |
|
{ |
215 |
|
struct ipc_entry *entry; |
216 |
|
struct task *task; |
217 |
|
kern_return_t kr; |
218 |
|
|
219 |
|
ipc_object_lock (THREAD_CURRENT()->task->ipc_object); |
220 |
|
kr = ipc_object_lookup (THREAD_CURRENT()->task->ipc_object, a->task_name, |
221 |
|
&entry); |
222 |
|
if (kr != KERN_SUCCESS) |
223 |
|
{ |
224 |
|
ipc_object_unlock (THREAD_CURRENT()->task->ipc_object); |
225 |
|
return kr; |
226 |
|
} |
227 |
|
|
228 |
|
if (entry->ie_port->kobject.type != IPC_KOBJECT_TYPE_TASK) |
229 |
|
{ |
230 |
|
ipc_object_unlock (THREAD_CURRENT()->task->ipc_object); |
231 |
|
return KERN_INVALID_TASK; |
232 |
|
} |
233 |
|
task = (struct task *) entry->ie_port->kobject.port; |
234 |
|
ipc_object_unlock (THREAD_CURRENT()->task->ipc_object); |
235 |
|
|
236 |
|
return port_destroy (task, a->name); |
237 |
} |
} |
238 |
|
|
239 |
/* Create a new kernel port. This port have not message queue since |
/* Create a new kernel port. This port have not message queue since |