- kdevelop3 project files
[lightOS.git] / kernel / port_manager.cpp
blob7444d1eab47eedd3302bb48d891ae3e39710fa9f
1 /*
2 lightOS kernel
3 Copyright (C) 2006-2009 Jörg Pfähler
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <kernel/arch/arch.hpp>
20 #include <kernel/log.hpp>
21 #include <kernel/process.hpp>
22 #include <kernel/port_manager.hpp>
23 #include <libarch/scoped_lock.hpp>
24 using namespace kernel;
25 using namespace std;
27 //FIXME: Use lists to speed things up
29 SINGLETON_INSTANCE(kernel::port_manager);
31 kernel::port_manager::port_manager()
35 kernel::port_manager::~port_manager()
39 libkernel::port_id_t port_manager::create(process &Process)
41 port *Port = new port(generatePortId(), &Process);
42 SCOPED_LOCK(mLock, scope);
43 list.push_back(Port);
44 return Port->id;
47 bool port_manager::create( process &Process,
48 libkernel::port_id_t Id)
50 SCOPED_LOCK(mLock, scope);
52 // Does the port already exist?
53 if (get_port_by_id(Id) != 0)
54 return false;
56 // Create the port
57 port *Port = new port(Id, &Process);
58 list.push_back(Port);
59 return true;
62 bool port_manager::send(libkernel::port_id_t port,
63 const libkernel::message_t &msg,
64 const process *Process)
66 LOCK(mLock);
68 // Does the destination port exist at all?
69 port_manager::port *Port = get_port_by_id(msg.port);
70 if (Port == 0)
72 UNLOCK(mLock);
73 return false;
76 // Is it the kernel that is sending a message?
77 if (Process != 0 && port != libkernel::message_port::kernel)
79 // Does the source port really exist and does the process own that port?
80 port_manager::port *srcPort = get_port_by_id(port);
81 if (srcPort == 0 || (Process != 0 && srcPort->owner != Process))
83 UNLOCK(mLock);
85 ERROR("port_manager::send(): source port #" << dec(port) << " non-existent or not owned by the process");
86 return false;
90 // Is the thread already waiting for this message?
91 // TODO: multiple wait messages not supported
92 if (Port->waiter != 0 &&
93 Port->waiter->status() == thread::wait_for_port &&
94 match(port, msg, Port->waiter_msg) == true)
96 // Unblock the thread
97 Port->waiter->unblock(msg.port, port, msg.type, msg.param1, msg.param2, msg.param3);
98 remove_thread_wait(*Port->waiter);
100 UNLOCK(mLock);
101 return true;
104 // Enqueue the message
105 libkernel::message_t *Msg = new libkernel::message_t(port, msg.type, msg.param1, msg.param2, msg.param3);
106 Port->msg.push_back(Msg);
108 UNLOCK(mLock);
109 return true;
112 bool port_manager::peek(libkernel::port_id_t port,
113 libkernel::message_t &msg,
114 const process &Process)
116 LOCK(mLock);
118 // Does the port exist and does it belong to this process?
119 port_manager::port *Port = get_port_by_id(port);
120 if (Port == 0 || Port->owner != &Process)
122 UNLOCK(mLock);
124 ERROR("port_manager::peek(): port #" << dec(port) << " non-existent or not owned by the process");
125 return false;
128 // Any messages in the queue?
129 if (Port->msg.size() == 0)
131 UNLOCK(mLock);
132 return false;
135 libkernel::message_t *Message = Port->msg.front();
136 msg = *Message;
137 Port->msg.erase(Port->msg.begin());
138 delete Message;
140 UNLOCK(mLock);
141 return true;
144 bool port_manager::get( libkernel::port_id_t port,
145 libkernel::message_t &msg,
146 thread &Thread)
148 if (peek(port, msg, Thread.getProcess()) == true)return true;
150 LOCK(mLock);
152 // Does the port exist and does it belong to this process?
153 port_manager::port *Port = get_port_by_id(port);
154 if (Port == 0 || Port->owner != &Thread.getProcess())
156 UNLOCK(mLock);
158 ERROR("port_manager::get(): port #" << dec(port) << " non-existent or not owned by the process");
159 return false;
162 Port->waiter = &Thread;
163 Port->waiter_msg.port = 0;
164 Port->waiter_msg.type = 0;
165 Port->waiter_msg.param1 = 0;
166 Port->waiter_msg.param2 = 0;
167 Port->waiter_msg.param3 = 0;
168 Port->waiter->block(thread::wait_for_port);
170 UNLOCK(mLock);
171 return false;
174 bool port_manager::wait(libkernel::port_id_t &port,
175 libkernel::message_t &msg,
176 thread &Thread)
178 LOCK(mLock);
180 size_t ports = 0;
182 // Go through the ports
183 for (vector<port_manager::port*>::iterator i=list.begin();i != list.end();i++)
184 if (i->waiter == &Thread)
186 // Go through the messages of that port
187 for (vector<libkernel::message_t*>::iterator y = i->msg.begin();y != i->msg.end();y++)
189 if (match(y->port, **y, i->waiter_msg) == true)
191 // Copy the message
192 port = i->id;
193 msg = **y;
195 // Delete the message
196 delete *y;
197 i->msg.erase(y);
199 // Remove this thread from all the other port waits
200 remove_thread_wait(*i->waiter);
202 UNLOCK(mLock);
203 return false;
206 ++ports;
209 // Are there any port the thread is waiting for?
210 if (ports == 0)
212 port = 0;
214 UNLOCK(mLock);
215 return false;
218 // Block the thread
219 Thread.block(thread::wait_for_port);
221 UNLOCK(mLock);
222 return true;
225 bool port_manager::add_wait(libkernel::port_id_t port,
226 const libkernel::message_t &msg,
227 thread &Thread)
229 LOCK(mLock);
231 // Does the port exist and does it belong to this process?
232 port_manager::port *Port = get_port_by_id(port);
233 if (Port == 0 || Port->owner != &Thread.getProcess())
235 UNLOCK(mLock);
237 ERROR("port_manager::add_wait(): port #" << dec(port) << " non-existent or not owned by the process");
238 return false;
241 // Set the waiter
242 Port->waiter = &Thread;
244 // Copy the message
245 Port->waiter_msg = msg;
247 UNLOCK(mLock);
248 return true;
251 bool port_manager::transfer(libkernel::port_id_t port,
252 const process &Process,
253 libkernel::process_id_t receiver)
255 LOCK(mLock);
257 // Does the port exist and dies it belong to this process
258 port_manager::port *Port = get_port_by_id(port);
259 if (Port == 0 || Port->owner != &Process)
261 UNLOCK(mLock);
263 ERROR("port_manager::transfer(): port #" << dec(port) << " non-existent or not owned by the process");
264 return false;
267 // Get the receiving process
268 process *recProcess = process::get_process(receiver);
269 if (recProcess == 0)
271 UNLOCK(mLock);
272 return false;
275 // Set the port owner
276 Port->owner = recProcess;
277 UNLOCK(mLock);
278 return true;
281 libkernel::process_id_t port_manager::get_processId(libkernel::port_id_t id)
283 LOCK(mLock);
285 // Find the port
286 port *Port = get_port_by_id(id);
287 if (Port == 0)
289 UNLOCK(mLock);
290 return 0;
293 // Save the pid
294 libkernel::process_id_t pid = Port->owner->getId();
296 UNLOCK(mLock);
297 return pid;
300 libkernel::thread_id_t port_manager::get_waiting_threadId(libkernel::port_id_t id)
302 LOCK(mLock);
304 // Find the port
305 port *Port = get_port_by_id(id);
306 if (Port == 0 ||
307 Port->waiter == 0)
309 UNLOCK(mLock);
310 return 0;
313 // Save the threadId
314 libkernel::thread_id_t tid = Port->waiter->getId();
316 UNLOCK(mLock);
317 return tid;
320 bool port_manager::destroy(libkernel::port_id_t port)
322 LOCK(mLock);
324 for (vector<port_manager::port*>::iterator i = list.begin();i != list.end();i++)
325 if (i->id == port)
327 destroy(*i);
328 list.erase(i);
330 UNLOCK(mLock);
331 return true;
334 UNLOCK(mLock);
335 return false;
338 void port_manager::destroy_process_ports(const process &Process)
340 LOCK(mLock);
342 for (vector<port_manager::port*>::iterator i=list.begin();i != list.end();)
343 if (i->owner == &Process)
345 destroy(*i);
346 i = list.erase(i);
348 else ++i;
350 UNLOCK(mLock);
353 port_manager::port *port_manager::get_port_by_id(libkernel::port_id_t id)
355 for (vector<port_manager::port*>::iterator i=list.begin();i != list.end();i++)
356 if (i->id == id)return *i;
357 return 0;
360 void port_manager::destroy(port *Port)
362 for (vector<libkernel::message_t*>::iterator y = Port->msg.begin();y != Port->msg.end();y++)
363 delete *y;
364 delete Port;
367 void port_manager::remove_thread_wait(const thread &Thread)
369 for (vector<port_manager::port*>::iterator i=list.begin();i != list.end();i++)
370 if (i->waiter == &Thread)
371 i->waiter = 0;
374 bool port_manager::match(libkernel::port_id_t port,
375 const libkernel::message_t &msg1,
376 const libkernel::message_t &msg2)
378 if (msg2.port != 0)
379 if (msg2.port != port)
380 return false;
381 if (msg2.type != 0)
382 if (MESSAGE_TYPE(msg2.type) != MESSAGE_TYPE(msg1.type))
383 return false;
384 if (msg2.param1 != 0)
385 if (msg2.param1 != msg1.param1)
386 return false;
387 if (msg2.param2 != 0)
388 if (msg2.param2 != msg1.param2)
389 return false;
390 if (msg2.param3 != 0)
391 if (msg2.param3 != msg1.param3)
392 return false;
393 return true;