shim_ipc_sysv.c 30 KB

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