shim_ipc_sysv.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. /* Copyright (C) 2014 Stony Brook University
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * shim_ipc_pid.c
  15. *
  16. * This file contains functions and callbacks to handle IPC of SYSV namespace.
  17. */
  18. #include <shim_internal.h>
  19. #include <shim_thread.h>
  20. #include <shim_ipc.h>
  21. #include <shim_checkpoint.h>
  22. #include <shim_sysv.h>
  23. #include <pal.h>
  24. #include <pal_error.h>
  25. #include <errno.h>
  26. #define SYSV_RANGE_SIZE 128
  27. #define SYSV_LEASE_TIME 1000
  28. #define KEY_HASH(k) ((k)->key)
  29. #define KEY_COMP(k1, k2) \
  30. ((k1)->key != (k2)->key || (k1)->type != (k2)->type)
  31. #define KEY_COPY(k1, k2) \
  32. do { (k1)->key = (k2)->key; (k1)->type = (k2)->type; } while (0)
  33. #define NS sysv
  34. #define NS_CAP SYSV
  35. #define NS_KEY struct sysv_key
  36. #define INCLUDE_IPC_NSIMPL
  37. #include "shim_ipc_nsimpl.h"
  38. int init_ns_sysv (void)
  39. {
  40. init_namespace();
  41. return 0;
  42. }
  43. DEFINE_PROFILE_INTERVAL(ipc_sysv_delres_send, ipc);
  44. DEFINE_PROFILE_INTERVAL(ipc_sysv_delres_callback, ipc);
  45. int ipc_sysv_delres_send (struct shim_ipc_port * port, IDTYPE dest,
  46. IDTYPE resid, enum sysv_type type)
  47. {
  48. BEGIN_PROFILE_INTERVAL();
  49. int ret = 0;
  50. bool owned = false;
  51. if (!port) {
  52. if ((ret = connect_owner(resid, &port, &dest)) < 0)
  53. goto out;
  54. owned = true;
  55. }
  56. if (!owned) {
  57. struct shim_ipc_msg * msg = create_ipc_msg_on_stack(
  58. IPC_SYSV_DELRES,
  59. sizeof(struct shim_ipc_sysv_delres),
  60. dest);
  61. struct shim_ipc_sysv_delres * msgin = (struct shim_ipc_sysv_delres *)
  62. &msg->msg;
  63. msgin->resid = resid;
  64. msgin->type = type;
  65. debug("ipc send to %u: IPC_SYSV_DELRES(%u, %s)\n", dest, resid,
  66. SYSV_TYPE_STR(type));
  67. ret = send_ipc_message(msg, port);
  68. goto out;
  69. }
  70. struct shim_ipc_msg_obj * msg = create_ipc_msg_duplex_on_stack(
  71. IPC_SYSV_DELRES,
  72. sizeof(struct shim_ipc_sysv_delres),
  73. dest);
  74. struct shim_ipc_sysv_delres * msgin = (struct shim_ipc_sysv_delres *)
  75. &msg->msg.msg;
  76. msgin->resid = resid;
  77. msgin->type = type;
  78. debug("ipc send to %u: IPC_SYSV_DELRES(%u, %s)\n", dest, resid,
  79. SYSV_TYPE_STR(type));
  80. ret = do_ipc_duplex(msg, port, NULL, NULL);
  81. put_ipc_port(port);
  82. out:
  83. SAVE_PROFILE_INTERVAL(ipc_sysv_delres_send);
  84. return ret;
  85. }
  86. int ipc_sysv_delres_callback (IPC_CALLBACK_ARGS)
  87. {
  88. BEGIN_PROFILE_INTERVAL();
  89. int ret = 0;
  90. struct shim_ipc_sysv_delres * msgin =
  91. (struct shim_ipc_sysv_delres *) &msg->msg;
  92. debug("ipc callback from %u: IPC_SYSV_DELRES(%u, %s)\n", msg->src,
  93. msgin->resid, SYSV_TYPE_STR(msgin->type));
  94. bool owned = false;
  95. ret = -ENOENT;
  96. switch(msgin->type) {
  97. case SYSV_MSGQ: {
  98. struct shim_msg_handle * msgq = get_msg_handle_by_id(msgin->resid);
  99. if (!msgq)
  100. goto out;
  101. owned = msgq->owned;
  102. ret = del_msg_handle(msgq);
  103. break;
  104. }
  105. case SYSV_SEM: {
  106. struct shim_sem_handle * sem = get_sem_handle_by_id(msgin->resid);
  107. if (!sem)
  108. goto out;
  109. owned = sem->owned;
  110. ret = del_sem_handle(sem);
  111. break;
  112. }
  113. default:
  114. ret = -ENOSYS;
  115. break;
  116. }
  117. if (!ret)
  118. ret = owned ? RESPONSE_CALLBACK : 0;
  119. out:
  120. SAVE_PROFILE_INTERVAL(ipc_sysv_delres_callback);
  121. return ret;
  122. }
  123. DEFINE_PROFILE_INTERVAL(ipc_sysv_movres_send, ipc);
  124. DEFINE_PROFILE_INTERVAL(ipc_sysv_movres_callback, ipc);
  125. int ipc_sysv_movres_send (struct sysv_client * client, IDTYPE owner,
  126. const char * uri, LEASETYPE lease, IDTYPE resid,
  127. enum sysv_type type)
  128. {
  129. BEGIN_PROFILE_INTERVAL();
  130. int ret = 0;
  131. int len = strlen(uri);
  132. struct shim_ipc_msg * msg = create_ipc_msg_on_stack(
  133. IPC_SYSV_MOVRES,
  134. sizeof(struct shim_ipc_sysv_movres) +
  135. len, client->vmid);
  136. struct shim_ipc_sysv_movres * msgin = (struct shim_ipc_sysv_movres *)
  137. &msg->msg;
  138. msgin->resid = resid;
  139. msgin->type = type;
  140. msgin->owner = owner;
  141. msgin->lease = lease;
  142. memcpy(msgin->uri, uri, len + 1);
  143. msg->seq = client->seq;
  144. debug("ipc send to %u: IPC_SYSV_MOVRES(%u, %s, %u, %s)\n", client->vmid,
  145. resid, SYSV_TYPE_STR(type), owner, uri);
  146. ret = send_ipc_message(msg, client->port);
  147. SAVE_PROFILE_INTERVAL(ipc_sysv_movres_send);
  148. return ret;
  149. }
  150. int ipc_sysv_movres_callback (IPC_CALLBACK_ARGS)
  151. {
  152. BEGIN_PROFILE_INTERVAL();
  153. int ret = 0;
  154. struct shim_ipc_sysv_movres * msgin =
  155. (struct shim_ipc_sysv_movres *) &msg->msg;
  156. debug("ipc callback from %u: IPC_SYSV_MOVRES(%u, %s, %u, %s)\n", msg->src,
  157. msgin->resid, SYSV_TYPE_STR(msgin->type), msgin->owner, msgin->uri);
  158. struct shim_ipc_msg_obj * obj = find_ipc_msg_duplex(port, msg->seq);
  159. if (!obj)
  160. goto out;
  161. switch(msgin->type) {
  162. case SYSV_MSGQ:
  163. case SYSV_SEM:
  164. obj->retval = -EAGAIN;
  165. break;
  166. default:
  167. ret = -ENOSYS;
  168. goto out;
  169. }
  170. add_sysv_subrange(msgin->resid, msgin->owner, msgin->uri, &msgin->lease);
  171. if (obj->thread)
  172. thread_wakeup(obj->thread);
  173. out:
  174. SAVE_PROFILE_INTERVAL(ipc_sysv_movres_callback);
  175. return ret;
  176. }
  177. DEFINE_PROFILE_INTERVAL(ipc_sysv_msgsnd_send, ipc);
  178. DEFINE_PROFILE_INTERVAL(ipc_sysv_msgsnd_callback, ipc);
  179. int ipc_sysv_msgsnd_send (struct shim_ipc_port * port, IDTYPE dest,
  180. IDTYPE msgid, long msgtype,
  181. const void * buf, size_t size, unsigned long seq)
  182. {
  183. BEGIN_PROFILE_INTERVAL();
  184. int ret = 0;
  185. bool owned = true;
  186. if (!dest) {
  187. if ((ret = connect_owner(msgid, &port, &dest)) < 0)
  188. goto out;
  189. owned = false;
  190. }
  191. struct shim_ipc_msg * msg = create_ipc_msg_on_stack(
  192. IPC_SYSV_MSGSND,
  193. sizeof(struct shim_ipc_sysv_msgsnd) +
  194. size, dest);
  195. struct shim_ipc_sysv_msgsnd * msgin =
  196. (struct shim_ipc_sysv_msgsnd *) &msg->msg;
  197. msgin->msgid = msgid;
  198. msgin->msgtype = msgtype;
  199. memcpy(msgin->msg, buf, size);
  200. msg->seq = seq;
  201. debug("ipc send to %u: IPC_SYSV_MSGSND(%u, %ld)\n", dest,
  202. msgid, msgtype);
  203. ret = send_ipc_message(msg, port);
  204. if (!owned)
  205. put_ipc_port(port);
  206. out:
  207. SAVE_PROFILE_INTERVAL(ipc_sysv_msgsnd_send);
  208. return ret;
  209. }
  210. int ipc_sysv_msgsnd_callback (IPC_CALLBACK_ARGS)
  211. {
  212. BEGIN_PROFILE_INTERVAL();
  213. int ret = 0;
  214. struct shim_ipc_sysv_msgsnd * msgin =
  215. (struct shim_ipc_sysv_msgsnd *) &msg->msg;
  216. debug("ipc callback from %u: IPC_SYSV_MSGSND(%u, %ld)\n", msg->src,
  217. msgin->msgid, msgin->msgtype);
  218. size_t size = msg->size - sizeof(*msg) - sizeof(*msgin);
  219. if (msg->seq) {
  220. struct shim_ipc_msg_obj * obj = find_ipc_msg_duplex(port, msg->seq);
  221. void * priv = obj ? obj->private : NULL;
  222. if (priv) {
  223. struct shim_ipc_sysv_msgrcv * rcv =
  224. (struct shim_ipc_sysv_msgrcv *) obj->msg.msg;
  225. if (size > rcv->size)
  226. size = rcv->size;
  227. memcpy(priv, msgin->msg, size);
  228. obj->retval = size;
  229. if (obj->thread)
  230. thread_wakeup(obj->thread);
  231. goto out;
  232. }
  233. }
  234. struct shim_msg_handle * msgq = get_msg_handle_by_id(msgin->msgid);
  235. if (!msgq) {
  236. ret = -ENOENT;
  237. goto out;
  238. }
  239. if (msg->seq) {
  240. ret = add_sysv_msg(msgq, msgin->msgtype, size, msgin->msg, NULL);
  241. } else {
  242. struct sysv_client src;
  243. src.port = port;
  244. src.vmid = msg->src;
  245. src.seq = msg->seq;
  246. ret = add_sysv_msg(msgq, msgin->msgtype, size, msgin->msg, &src);
  247. }
  248. out:
  249. SAVE_PROFILE_INTERVAL(ipc_sysv_msgsnd_callback);
  250. return ret;
  251. }
  252. DEFINE_PROFILE_INTERVAL(ipc_sysv_msgrcv_send, ipc);
  253. DEFINE_PROFILE_INTERVAL(ipc_sysv_msgrcv_callback, ipc);
  254. int ipc_sysv_msgrcv_send (IDTYPE msgid, long msgtype, int flags, void * buf,
  255. size_t size)
  256. {
  257. BEGIN_PROFILE_INTERVAL();
  258. IDTYPE owner;
  259. struct shim_ipc_port * port = NULL;
  260. int ret = 0;
  261. if ((ret = connect_owner(msgid, &port, &owner)) < 0)
  262. goto out;
  263. if (owner == cur_process.vmid) {
  264. ret = -EAGAIN;
  265. goto out;
  266. }
  267. assert(port);
  268. struct shim_ipc_msg_obj * msg = create_ipc_msg_duplex_on_stack(
  269. IPC_SYSV_MSGRCV,
  270. sizeof(struct shim_ipc_sysv_msgrcv),
  271. true);
  272. struct shim_ipc_sysv_msgrcv * msgin =
  273. (struct shim_ipc_sysv_msgrcv *) &msg->msg.msg;
  274. msgin->msgid = msgid;
  275. msgin->msgtype = msgtype;
  276. msgin->size = size;
  277. msgin->flags = flags;
  278. debug("ipc send to %u: IPC_SYSV_MSGRCV(%u, %ld)\n", owner,
  279. msgid, msgtype);
  280. ret = do_ipc_duplex(msg, port, NULL, buf);
  281. put_ipc_port(port);
  282. out:
  283. SAVE_PROFILE_INTERVAL(ipc_sysv_msgrcv_send);
  284. return ret;
  285. }
  286. int ipc_sysv_msgrcv_callback (IPC_CALLBACK_ARGS)
  287. {
  288. BEGIN_PROFILE_INTERVAL();
  289. int ret = 0;
  290. struct shim_ipc_sysv_msgrcv * msgin =
  291. (struct shim_ipc_sysv_msgrcv *) &msg->msg;
  292. debug("ipc callback from %u: IPC_SYSV_MSGRCV(%u, %ld)\n", msg->src,
  293. msgin->msgid, msgin->msgtype);
  294. struct shim_msg_handle * msgq = get_msg_handle_by_id(msgin->msgid);
  295. if (!msgq) {
  296. ret = -ENOENT;
  297. goto out;
  298. }
  299. void * buf = __alloca(msgin->size);
  300. struct sysv_client src;
  301. src.port = port;
  302. src.vmid = msg->src;
  303. src.seq = msg->seq;
  304. ret = get_sysv_msg(msgq, msgin->msgtype, msgin->size, buf, msgin->flags,
  305. &src);
  306. if (ret > 0) {
  307. size_t size = ret;
  308. ret = ipc_sysv_msgsnd_send(port, msg->src, msgin->msgid, msgin->msgtype,
  309. buf, size, msg->seq);
  310. }
  311. put_msg_handle(msgq);
  312. out:
  313. SAVE_PROFILE_INTERVAL(ipc_sysv_msgrcv_callback);
  314. return ret;
  315. }
  316. DEFINE_PROFILE_INTERVAL(ipc_sysv_msgmov_send, ipc);
  317. DEFINE_PROFILE_INTERVAL(ipc_sysv_msgmov_callback, ipc);
  318. int ipc_sysv_msgmov_send (struct shim_ipc_port * port, IDTYPE dest,
  319. IDTYPE msgid, LEASETYPE lease,
  320. struct sysv_score * scores, int nscores)
  321. {
  322. BEGIN_PROFILE_INTERVAL();
  323. struct shim_ipc_msg * msg =
  324. create_ipc_msg_on_stack(IPC_SYSV_MSGMOV,
  325. sizeof(struct shim_ipc_sysv_msgmov) +
  326. sizeof(struct sysv_score) * nscores,
  327. dest);
  328. struct shim_ipc_sysv_msgmov * msgin =
  329. (struct shim_ipc_sysv_msgmov *) &msg->msg;
  330. msgin->msgid = msgid;
  331. msgin->lease = lease;
  332. msgin->nscores = nscores;
  333. if (nscores)
  334. memcpy(msgin->scores, scores, sizeof(struct sysv_score) * nscores);
  335. debug("ipc send to %u: IPC_SYSV_MSGMOV(%d)\n", dest, msgid);
  336. int ret = send_ipc_message(msg, port);
  337. SAVE_PROFILE_INTERVAL(ipc_sysv_msgmov_send);
  338. return ret;
  339. }
  340. int ipc_sysv_msgmov_callback (IPC_CALLBACK_ARGS)
  341. {
  342. BEGIN_PROFILE_INTERVAL();
  343. int ret = 0;
  344. struct shim_ipc_sysv_msgmov * msgin =
  345. (struct shim_ipc_sysv_msgmov *) &msg->msg;
  346. debug("ipc callback from %u: IPC_SYSV_MSGMOV(%d)\n", msg->src,
  347. msgin->msgid);
  348. struct shim_msg_handle * msgq = get_msg_handle_by_id(msgin->msgid);
  349. if (!msgq) {
  350. ret = -ENOENT;
  351. goto out;
  352. }
  353. struct shim_handle * hdl = container_of(msgq, struct shim_handle,
  354. info.msg);
  355. lock(&hdl->lock);
  356. int nscores = (msgin->nscores > MAX_SYSV_CLIENTS) ?
  357. MAX_SYSV_CLIENTS : msgin->nscores;
  358. if (nscores)
  359. memcpy(msgq->scores, msgin->scores, nscores);
  360. if (nscores < MAX_SYSV_CLIENTS)
  361. memset(msgq->scores + nscores, 0,
  362. sizeof(struct sysv_score) * (MAX_SYSV_CLIENTS - nscores));
  363. unlock(&hdl->lock);
  364. ret = recover_msg_ownership(msgq);
  365. struct shim_ipc_info * info;
  366. if (!create_ipc_location(&info)) {
  367. add_sysv_subrange(msgin->msgid, info->vmid, qstrgetstr(&info->uri),
  368. &msgin->lease);
  369. put_ipc_info(info);
  370. }
  371. put_msg_handle(msgq);
  372. out:
  373. SAVE_PROFILE_INTERVAL(ipc_sysv_msgmov_callback);
  374. return ret;
  375. }
  376. DEFINE_PROFILE_INTERVAL(ipc_sysv_semop_send, ipc);
  377. DEFINE_PROFILE_INTERVAL(ipc_sysv_semop_callback, ipc);
  378. int ipc_sysv_semop_send (IDTYPE semid, struct sembuf * sops, int nsops,
  379. unsigned long timeout, unsigned long * seq)
  380. {
  381. BEGIN_PROFILE_INTERVAL();
  382. IDTYPE owner;
  383. struct shim_ipc_port * port = NULL;
  384. int ret = 0;
  385. bool waitforreply = false;
  386. for (int i = 0 ; i < nsops ; i++)
  387. if (sops[i].sem_op <= 0) {
  388. waitforreply = true;
  389. break;
  390. }
  391. if ((ret = connect_owner(semid, &port, &owner)) < 0)
  392. goto out;
  393. if (owner == cur_process.vmid) {
  394. ret = -EAGAIN;
  395. goto out;
  396. }
  397. assert(port);
  398. if (!waitforreply) {
  399. struct shim_ipc_msg * msg = create_ipc_msg_on_stack(
  400. IPC_SYSV_SEMOP,
  401. sizeof(struct shim_ipc_sysv_semop) +
  402. sizeof(struct sembuf) * nsops,
  403. owner);
  404. struct shim_ipc_sysv_semop * msgin =
  405. (struct shim_ipc_sysv_semop *) &msg->msg;
  406. msgin->semid = semid;
  407. msgin->timeout = timeout;
  408. msgin->nsops = nsops;
  409. memcpy(msgin->sops, sops, sizeof(struct sembuf) * nsops);
  410. msg->seq = *seq;
  411. debug("ipc send to %u: IPC_SYSV_SEMOP(%u, %ld, %u)\n", owner, semid,
  412. timeout, nsops);
  413. ret = send_ipc_message(msg, port);
  414. put_ipc_port(port);
  415. goto out;
  416. }
  417. struct shim_ipc_msg_obj * msg = create_ipc_msg_duplex_on_stack(
  418. IPC_SYSV_SEMOP,
  419. sizeof(struct shim_ipc_sysv_semop) +
  420. sizeof(struct sembuf) * nsops,
  421. owner);
  422. struct shim_ipc_sysv_semop * msgin =
  423. (struct shim_ipc_sysv_semop *) &msg->msg.msg;
  424. msgin->semid = semid;
  425. msgin->timeout = timeout;
  426. msgin->nsops = nsops;
  427. memcpy(msgin->sops, sops, sizeof(struct sembuf) * nsops);
  428. msg->msg.seq = *seq;
  429. debug("ipc send to %u: IPC_SYSV_SEMOP(%u, %ld, %u)\n", owner, semid,
  430. timeout, nsops);
  431. ret = do_ipc_duplex(msg, port, seq, NULL);
  432. put_ipc_port(port);
  433. out:
  434. SAVE_PROFILE_INTERVAL(ipc_sysv_semop_send);
  435. return ret;
  436. }
  437. int ipc_sysv_semop_callback (IPC_CALLBACK_ARGS)
  438. {
  439. BEGIN_PROFILE_INTERVAL();
  440. int ret = 0;
  441. struct shim_ipc_sysv_semop * msgin =
  442. (struct shim_ipc_sysv_semop *) &msg->msg;
  443. debug("ipc callback from %u: IPC_SYSV_SEMOP(%u, %ld, %u)\n", msg->src,
  444. msgin->semid, msgin->timeout, msgin->nsops);
  445. struct shim_sem_handle * sem = get_sem_handle_by_id(msgin->semid);
  446. if (!sem) {
  447. ret = -ENOENT;
  448. goto out;
  449. }
  450. struct sysv_client client;
  451. client.port = port;
  452. client.vmid = msg->src;
  453. client.seq = msg->seq;
  454. ret = submit_sysv_sem(sem, msgin->sops, msgin->nsops, msgin->timeout,
  455. &client);
  456. put_sem_handle(sem);
  457. out:
  458. SAVE_PROFILE_INTERVAL(ipc_sysv_semop_callback);
  459. return ret;
  460. }
  461. DEFINE_PROFILE_INTERVAL(ipc_sysv_semctl_send, ipc);
  462. DEFINE_PROFILE_INTERVAL(ipc_sysv_semctl_callback, ipc);
  463. int ipc_sysv_semctl_send (IDTYPE semid, int semnum, int cmd, void * vals,
  464. int valsize)
  465. {
  466. BEGIN_PROFILE_INTERVAL();
  467. IDTYPE owner;
  468. struct shim_ipc_port * port = NULL;
  469. int ret = 0;
  470. if ((ret = connect_owner(semid, &port, &owner)) < 0)
  471. goto out;
  472. int ctlvalsize = (cmd == SETALL || cmd == SETVAL) ? valsize : 0;
  473. struct shim_ipc_msg_obj * msg = create_ipc_msg_duplex_on_stack(
  474. IPC_SYSV_SEMCTL,
  475. sizeof(struct shim_ipc_sysv_semctl) +
  476. ctlvalsize,
  477. owner);
  478. struct shim_ipc_sysv_semctl * msgin =
  479. (struct shim_ipc_sysv_semctl *) &msg->msg.msg;
  480. msgin->semid = semid;
  481. msgin->semnum = semnum;
  482. msgin->cmd = cmd;
  483. msgin->valsize = ctlvalsize;
  484. if (ctlvalsize)
  485. memcpy(msgin->vals, vals, ctlvalsize);
  486. debug("ipc send to %u: IPC_SYSV_SEMCTL(%u, %d, %d)\n", owner, semid,
  487. semnum, cmd);
  488. ret = do_ipc_duplex(msg, port, NULL, vals);
  489. put_ipc_port(port);
  490. out:
  491. SAVE_PROFILE_INTERVAL(ipc_sysv_semctl_send);
  492. return ret;
  493. }
  494. int ipc_sysv_semctl_callback (IPC_CALLBACK_ARGS)
  495. {
  496. BEGIN_PROFILE_INTERVAL();
  497. int ret = 0;
  498. struct shim_ipc_sysv_semctl * msgin =
  499. (struct shim_ipc_sysv_semctl *) &msg->msg;
  500. debug("ipc callback from %u: IPC_SYSV_SEMCTL(%u, %d, %d)\n", msg->src,
  501. msgin->semid, msgin->semnum, msgin->cmd);
  502. struct shim_sem_handle * sem = get_sem_handle_by_id(msgin->semid);
  503. if (!sem) {
  504. ret = -ENOENT;
  505. goto out;
  506. }
  507. void * vals = NULL;
  508. int valsize;
  509. switch(msgin->cmd) {
  510. case GETALL: {
  511. unsigned short * allsems = __alloca(sizeof(unsigned short) *
  512. sem->nsems);
  513. for (int i = 0 ; i < sem->nsems ; i++)
  514. allsems[i] = sem->sems[i].val;
  515. vals = allsems;
  516. valsize = sizeof(unsigned short) * sem->nsems;
  517. goto semret;
  518. }
  519. case GETNCNT:
  520. vals = &sem->sems[msgin->semnum].ncnt;
  521. valsize = sizeof(unsigned short);
  522. goto semret;
  523. case GETPID:
  524. vals = &sem->sems[msgin->semnum].pid;
  525. valsize = sizeof(IDTYPE);
  526. goto semret;
  527. case GETVAL:
  528. vals = &sem->sems[msgin->semnum].val;
  529. valsize = sizeof(unsigned short);
  530. goto semret;
  531. case GETZCNT:
  532. vals = &sem->sems[msgin->semnum].zcnt;
  533. valsize = sizeof(unsigned short);
  534. break;
  535. case SETALL: {
  536. if (msgin->valsize != sizeof(unsigned short) * sem->nsems) {
  537. ret = -EINVAL;
  538. break;
  539. }
  540. unsigned short * vals = (void *) msgin->vals;
  541. for (int i = 0 ; i < sem->nsems ; i++)
  542. sem->sems[i].val = vals[i];
  543. ret = RESPONSE_CALLBACK;
  544. break;
  545. }
  546. case SETVAL: {
  547. ret = -EINVAL;
  548. if (msgin->valsize != sizeof(unsigned short))
  549. break;
  550. if (msgin->semnum >= sem->nsems)
  551. break;
  552. sem->sems[msgin->semnum].val = *((int *) msgin->vals);
  553. ret = RESPONSE_CALLBACK;
  554. break;
  555. }
  556. default:
  557. ret = -ENOSYS;
  558. break;
  559. }
  560. put_sem_handle(sem);
  561. goto out;
  562. semret:
  563. ret = ipc_sysv_semret_send(port, msg->src, vals, valsize,
  564. msg->seq);
  565. out:
  566. SAVE_PROFILE_INTERVAL(ipc_sysv_semctl_callback);
  567. return ret;
  568. }
  569. DEFINE_PROFILE_INTERVAL(ipc_sysv_semret_send, ipc);
  570. DEFINE_PROFILE_INTERVAL(ipc_sysv_semret_callback, ipc);
  571. int ipc_sysv_semret_send (struct shim_ipc_port * port, IDTYPE dest, void * vals,
  572. int valsize, unsigned long seq)
  573. {
  574. BEGIN_PROFILE_INTERVAL();
  575. int ret = 0;
  576. struct shim_ipc_msg * msg = create_ipc_msg_on_stack(
  577. IPC_SYSV_SEMRET,
  578. sizeof(struct shim_ipc_sysv_semret) +
  579. valsize,
  580. dest);
  581. struct shim_ipc_sysv_semret * msgin =
  582. (struct shim_ipc_sysv_semret *) &msg->msg;
  583. msgin->valsize = valsize;
  584. memcpy(msgin->vals, vals, valsize);
  585. msg->seq = seq;
  586. debug("ipc send to %u: IPC_SYSV_SEMRET\n", dest);
  587. ret = send_ipc_message(msg, port);
  588. SAVE_PROFILE_INTERVAL(ipc_sysv_semret_send);
  589. return ret;
  590. }
  591. int ipc_sysv_semret_callback (IPC_CALLBACK_ARGS)
  592. {
  593. BEGIN_PROFILE_INTERVAL();
  594. struct shim_ipc_sysv_semret * semret =
  595. (struct shim_ipc_sysv_semret *) &msg->msg;
  596. debug("ipc callback from %u: IPC_SYSV_SEMRET\n", msg->src);
  597. struct shim_ipc_msg_obj * obj = find_ipc_msg_duplex(port, msg->seq);
  598. if (obj) {
  599. struct shim_ipc_sysv_semctl * semctl =
  600. (struct shim_ipc_sysv_semctl *) &obj->msg.msg;
  601. void * vals = obj->private;
  602. if (vals) {
  603. switch(semctl->cmd) {
  604. case GETALL:
  605. case GETNCNT:
  606. case GETPID:
  607. case GETVAL:
  608. case GETZCNT: {
  609. int retvalsize = semret->valsize;
  610. if (retvalsize > semctl->valsize)
  611. retvalsize = semctl->valsize;
  612. memcpy(vals, semret->vals, retvalsize);
  613. break;
  614. }
  615. }
  616. }
  617. if (obj->thread)
  618. thread_wakeup(obj->thread);
  619. }
  620. SAVE_PROFILE_INTERVAL(ipc_sysv_semret_callback);
  621. return 0;
  622. }
  623. DEFINE_PROFILE_INTERVAL(ipc_sysv_semmov_send, ipc);
  624. DEFINE_PROFILE_INTERVAL(ipc_sysv_semmov_callback, ipc);
  625. int ipc_sysv_semmov_send (struct shim_ipc_port * port, IDTYPE dest,
  626. IDTYPE semid, LEASETYPE lease,
  627. struct sem_backup * sems, int nsems,
  628. struct sem_client_backup * srcs, int nsrcs,
  629. struct sysv_score * scores, int nscores)
  630. {
  631. BEGIN_PROFILE_INTERVAL();
  632. struct shim_ipc_msg * msg =
  633. create_ipc_msg_on_stack(IPC_SYSV_SEMMOV,
  634. sizeof(struct shim_ipc_sysv_semmov) +
  635. sizeof(struct sem_backup) * nsems +
  636. sizeof(struct sem_client_backup) * nsrcs +
  637. sizeof(struct sysv_score) * nscores,
  638. dest);
  639. struct shim_ipc_sysv_semmov * msgin =
  640. (struct shim_ipc_sysv_semmov *) &msg->msg;
  641. msgin->semid = semid;
  642. msgin->lease = lease;
  643. msgin->nsems = nsems;
  644. msgin->nsrcs = nsrcs;
  645. msgin->nscores = nscores;
  646. memcpy(&msgin->sems, sems, sizeof(struct sem_backup) * nsems);
  647. memcpy((void *) msgin->sems + sizeof(struct sem_backup) * nsems,
  648. srcs, sizeof(struct sem_client_backup) * nsrcs);
  649. memcpy((void *) msgin->sems + sizeof(struct sem_backup) * nsems +
  650. sizeof(struct sem_client_backup) * nsrcs,
  651. scores, sizeof(struct sysv_score) * nscores);
  652. debug("ipc send to : IPC_SYSV_SEMMOV(%d)\n", semid);
  653. int ret = send_ipc_message(msg, port);
  654. SAVE_PROFILE_INTERVAL(ipc_sysv_semmov_send);
  655. return ret;
  656. }
  657. int ipc_sysv_semmov_callback (IPC_CALLBACK_ARGS)
  658. {
  659. BEGIN_PROFILE_INTERVAL();
  660. int ret = 0;
  661. struct shim_ipc_sysv_semmov * msgin =
  662. (struct shim_ipc_sysv_semmov *) &msg->msg;
  663. debug("ipc callback from %u: IPC_SYSV_SEMMOV(%d)\n", msg->src,
  664. msgin->semid);
  665. struct sem_backup * sems = msgin->sems;
  666. struct sem_client_backup * clients =
  667. (struct sem_client_backup *) (sems + msgin->nsems);
  668. struct sysv_score * scores =
  669. (struct sysv_score *) (clients + msgin->nsrcs);
  670. struct shim_sem_handle * sem = get_sem_handle_by_id(msgin->semid);
  671. if (!sem) {
  672. ret = -ENOENT;
  673. goto out;
  674. }
  675. struct shim_handle * hdl = container_of(sem, struct shim_handle,
  676. info.sem);
  677. lock(&hdl->lock);
  678. int nscores = (msgin->nscores > MAX_SYSV_CLIENTS) ?
  679. MAX_SYSV_CLIENTS : msgin->nscores;
  680. if (nscores)
  681. memcpy(sem->scores, scores, nscores);
  682. if (nscores < MAX_SYSV_CLIENTS)
  683. memset(sem->scores + nscores, 0,
  684. sizeof(struct sysv_score) * (MAX_SYSV_CLIENTS - nscores));
  685. unlock(&hdl->lock);
  686. ret = recover_sem_ownership(sem, sems, msgin->nsems, clients,
  687. msgin->nsrcs);
  688. struct shim_ipc_info * info;
  689. if (!create_ipc_location(&info)) {
  690. add_sysv_subrange(msgin->semid, info->vmid, qstrgetstr(&info->uri),
  691. &msgin->lease);
  692. put_ipc_info(info);
  693. }
  694. put_sem_handle(sem);
  695. out:
  696. SAVE_PROFILE_INTERVAL(ipc_sysv_semmov_callback);
  697. return ret;
  698. }
  699. #ifdef USE_SHARED_SEMAPHORE
  700. DEFINE_PROFILE_INTERVAL(ipc_sysv_semquery_send, ipc);
  701. DEFINE_PROFILE_INTERVAL(ipc_sysv_semquery_callback, ipc);
  702. int ipc_sysv_semquery_send (IDTYPE semid, int * nsems,
  703. PAL_NUM ** host_sem_ids)
  704. {
  705. BEGIN_PROFILE_INTERVAL();
  706. int ret = 0;
  707. IDTYPE dest;
  708. struct shim_ipc_port * port = NULL;
  709. if ((ret = connect_owner(semid, &port, &dest)) < 0)
  710. goto out;
  711. if (dest == cur_process.vmid) {
  712. ret = -EAGAIN;
  713. goto out;
  714. }
  715. assert(port);
  716. struct shim_ipc_msg_obj * msg = create_ipc_msg_duplex_on_stack(
  717. IPC_SYSV_SEMQUERY,
  718. sizeof(struct shim_ipc_sysv_semquery),
  719. dest);
  720. struct shim_ipc_sysv_semquery * msgin =
  721. (struct shim_ipc_sysv_semquery *) &msg->msg.msg;
  722. msgin->semid = semid;
  723. debug("ipc send to %u: IPC_SYSV_SEMQUERY(%u)\n", dest, semid);
  724. ret = do_ipc_duplex(msg, port, NULL, host_sem_ids);
  725. put_ipc_port(port);
  726. if (ret >= 0) {
  727. *nsems = ret;
  728. ret = 0;
  729. }
  730. out:
  731. SAVE_PROFILE_INTERVAL(ipc_sysv_semquery_send);
  732. return ret;
  733. }
  734. int ipc_sysv_semquery_callback (IPC_CALLBACK_ARGS)
  735. {
  736. BEGIN_PROFILE_INTERVAL();
  737. int ret = 0;
  738. struct shim_ipc_sysv_semquery * msgin =
  739. (struct shim_ipc_sysv_semquery *) &msg->msg;
  740. debug("ipc callback from %u: IPC_SYSV_SEMQUERY(%u)\n", msg->src,
  741. msgin->semid);
  742. struct shim_sem_handle * sem = get_sem_handle_by_id(msgin->semid);
  743. if (!sem) {
  744. ret = -ENOENT;
  745. goto out;
  746. }
  747. ret = send_sem_host_ids(sem, port, msg->src, msg->seq);
  748. put_sem_handle(sem);
  749. out:
  750. SAVE_PROFILE_INTERVAL(ipc_sysv_semreply_callback);
  751. return ret;
  752. }
  753. DEFINE_PROFILE_INTERVAL(ipc_sysv_semreply_send, ipc);
  754. DEFINE_PROFILE_INTERVAL(ipc_sysv_semreply_callback, ipc);
  755. int ipc_sysv_semreply_send (struct shim_ipc_port * port, IDTYPE dest,
  756. IDTYPE semid, int nsems, PAL_NUM * host_sem_ids,
  757. unsigned long seq)
  758. {
  759. BEGIN_PROFILE_INTERVAL();
  760. int ret = 0;
  761. struct shim_ipc_msg * msg = create_ipc_msg_on_stack(
  762. IPC_SYSV_SEMREPLY,
  763. sizeof(struct shim_ipc_sysv_semreply)
  764. + sizeof(PAL_NUM) * nsems,
  765. dest);
  766. struct shim_ipc_sysv_semreply * msgin =
  767. (struct shim_ipc_sysv_semreply *) &msg->msg;
  768. msgin->semid = semid;
  769. msgin->nsems = nsems;
  770. if (nsems)
  771. memcpy(msgin->host_sem_ids, host_sem_ids, sizeof(PAL_NUM) * nsems);
  772. msg->seq = seq;
  773. debug("ipc send to %u: IPC_SYSV_SEMREPLY(%u, %d)\n", dest, semid, nsems);
  774. ret = send_ipc_message(msg, port);
  775. SAVE_PROFILE_INTERVAL(ipc_sysv_semreply_send);
  776. return ret;
  777. }
  778. int ipc_sysv_semreply_callback (IPC_CALLBACK_ARGS)
  779. {
  780. BEGIN_PROFILE_INTERVAL();
  781. int ret = 0;
  782. struct shim_ipc_sysv_semreply * msgin =
  783. (struct shim_ipc_sysv_semreply *) &msg->msg;
  784. debug("ipc callback from %u: IPC_SYSV_SEMREPLY(%u, %d)\n", msg->src,
  785. msgin->semid, msgin->nsems);
  786. struct shim_ipc_msg_obj * obj = find_ipc_msg_duplex(port, msg->seq);
  787. if (!obj)
  788. goto out;
  789. PAL_NUM ** semids = obj->private;
  790. if (semids)
  791. *semids = malloc_copy(msgin->host_sem_ids,
  792. sizeof(PAL_NUM) * msgin->nsems);
  793. obj->retval = msgin->nsems;
  794. if (obj->thread)
  795. thread_wakeup(obj->thread);
  796. out:
  797. SAVE_PROFILE_INTERVAL(ipc_sysv_semreply_callback);
  798. return ret;
  799. }
  800. #endif /* USE_SHARED_SEMAPHORE */
  801. int __balance_sysv_score (struct sysv_balance_policy * policy,
  802. struct shim_handle * hdl,
  803. struct sysv_score * scores, int nscores,
  804. struct sysv_client * src, long score)
  805. {
  806. struct sysv_score * s = scores;
  807. struct sysv_score * last = scores + nscores;
  808. for ( ; s < last && !s->vmid ; s++);
  809. struct sysv_score * free = s > scores ? scores : NULL;
  810. struct sysv_score * highest = s < last ? s : NULL;
  811. struct sysv_score * lowest = highest;
  812. struct sysv_score * owner = NULL;
  813. struct sysv_score * chosen = NULL;
  814. for ( ; s < last ; s++) {
  815. if (!s->vmid) {
  816. if (!free)
  817. free = s;
  818. continue;
  819. }
  820. if (s->score >= highest->score)
  821. highest = s;
  822. if (s->score < lowest->score)
  823. lowest = s;
  824. if (src) {
  825. if (s->vmid == cur_process.vmid)
  826. owner = s;
  827. if (s->vmid == src->vmid) {
  828. chosen = s;
  829. continue;
  830. }
  831. } else {
  832. if (s->vmid == cur_process.vmid) {
  833. owner = chosen = s;
  834. continue;
  835. }
  836. }
  837. s->score = (s->score >= policy->score_decay) ?
  838. s->score - policy->score_decay : 0;
  839. debug("balance: %u => %ld\n", s->vmid, s->score);
  840. }
  841. if (!chosen) {
  842. chosen = free ? : lowest;
  843. chosen->vmid = src ? src->vmid : cur_process.vmid;
  844. chosen->score = 0;
  845. }
  846. chosen->score += score;
  847. if (chosen->score > policy->score_max)
  848. chosen->score = policy->score_max;
  849. debug("balance: %u => %ld\n", chosen->vmid, chosen->score);
  850. if (!src || chosen != highest ||
  851. chosen->score < (owner ? owner->score : 0) + policy->balance_threshold)
  852. return 0;
  853. return policy->migrate(hdl, src);
  854. }