shim_ipc_sysv.c 30 KB

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