sampletask.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2006 Red Hat, Inc.
  3. * All rights reserved.
  4. *
  5. * License: GPL (version 3 or any later version).
  6. * See LICENSE for details.
  7. * END COPYRIGHT BLOCK **/
  8. /*
  9. * sample task plugin
  10. *
  11. * [How to set up the plugin for testing]
  12. * 1. compile and package with the other plugins
  13. * 2. put the plugin libsampletask-plugin.so at <prefix>/usr/lib/<PACKAGE_NAME>/plugins
  14. * 3. register it as a plugin in dse.ldif
  15. * Plugin entry:
  16. * dn: cn=sampletask,cn=plugins,cn=config
  17. * objectClass: top
  18. * objectClass: nsSlapdPlugin
  19. * objectClass: extensibleObject
  20. * cn: sampletask
  21. * nsslapd-pluginPath: libsampletask-plugin
  22. * nsslapd-pluginInitfunc: sampletask_init
  23. * nsslapd-pluginType: object
  24. * nsslapd-pluginEnabled: on
  25. * nsslapd-pluginId: sampletask
  26. * nsslapd-pluginVersion: <plugin_version>
  27. * nsslapd-pluginVendor: <vendor name>
  28. * nsslapd-pluginDescription: Sample task plugin
  29. *
  30. * 4. create a config task entry in dse.ldif
  31. * Task entry:
  32. * dn: cn=sampletask, cn=tasks, cn=config
  33. * objectClass: top
  34. * objectClass: extensibleObject
  35. * cn: sampletask
  36. *
  37. * 5. to invoke the sample task, run the command line:
  38. * $ ./ldapmodify -h <host> -p <port> -D "cn=Directory Manager" -w <pw> -a
  39. * dn: cn=sampletask 0, cn=sample task, cn=tasks, cn=config
  40. * objectClass: top
  41. * objectClass: extensibleObject
  42. * cn: sample task 0
  43. * myarg: sample task myarg
  44. *
  45. * Result is in the errors log
  46. * [...] - Sample task starts (arg: sample task myarg) ...
  47. * [...] - Sample task finished.
  48. */
  49. #include "slapi-plugin.h"
  50. #include "nspr.h"
  51. static int task_sampletask_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
  52. static int task_sampletask_start(Slapi_PBlock *pb);
  53. /*
  54. * Init function
  55. * Specified in the plugin entry as "nsslapd-pluginInitfunc: sampletask_init"
  56. */
  57. int
  58. sampletask_init(Slapi_PBlock *pb)
  59. {
  60. int rc = 0;
  61. rc = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  62. (void *)SLAPI_PLUGIN_VERSION_03);
  63. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
  64. (void *)task_sampletask_start);
  65. return rc;
  66. }
  67. /*
  68. * Task start function
  69. * Register the function task_sampletask_add, which invokes the task on demand.
  70. */
  71. static int
  72. task_sampletask_start(Slapi_PBlock *pb)
  73. {
  74. int rc = slapi_task_register_handler("sample task", task_sampletask_add);
  75. return rc;
  76. }
  77. /*
  78. * Task thread
  79. * Not necessary be a thread, but it'd not disturb the server's other jobs.
  80. */
  81. static void
  82. task_sampletask_thread(void *arg)
  83. {
  84. Slapi_Task *task = (Slapi_Task *)arg;
  85. char *myarg = NULL;
  86. int i, rv = 0;
  87. int total_work = 3;
  88. /* fetch our argument from the task */
  89. myarg = (char *)slapi_task_get_data(task);
  90. /* update task state to show it's running */
  91. slapi_task_begin(task, total_work);
  92. slapi_task_log_notice(task, "Sample task starts (arg: %s) ...\n", myarg);
  93. slapi_log_err(SLAPI_LOG_ERR, "sampletask", "Sample task starts (arg: %s) ...\n", myarg);
  94. /* real work would be done here */
  95. for (i = 0; i < total_work; i++) {
  96. PR_Sleep(10000);
  97. slapi_task_inc_progress(task);
  98. }
  99. /* update task state to say we're finished */
  100. slapi_task_log_notice(task, "Sample task finished.");
  101. slapi_task_log_status(task, "Sample task finished.");
  102. slapi_log_err(SLAPI_LOG_ERR, "sampletask", "Sample task finished.\n");
  103. /* this will queue the destruction of the task */
  104. slapi_task_finish(task, rv);
  105. }
  106. static void
  107. task_sampletask_destructor(Slapi_Task *task)
  108. {
  109. if (task) {
  110. char *myarg = (char *)slapi_task_get_data(task);
  111. if (myarg) {
  112. slapi_ch_free_string(&myarg);
  113. }
  114. }
  115. }
  116. /*
  117. * Invoked when the task instance is added by the client (step 5 of the comment)
  118. * Get the necessary attributes from the task entry, and spawns a thread to do
  119. * the task.
  120. */
  121. static int
  122. task_sampletask_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
  123. {
  124. PRThread *thread = NULL;
  125. const char *cn;
  126. int rv = SLAPI_DSE_CALLBACK_OK;
  127. Slapi_PBlock *mypb = NULL;
  128. Slapi_Task *task = NULL;
  129. const char *myarg;
  130. *returncode = LDAP_SUCCESS;
  131. if ((cn = fetch_attr(e, "cn", NULL)) == NULL) {
  132. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  133. rv = SLAPI_DSE_CALLBACK_ERROR;
  134. goto out;
  135. }
  136. /* get arg(s) */
  137. if ((myarg = fetch_attr(e, "myarg", NULL)) == NULL) {
  138. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  139. rv = SLAPI_DSE_CALLBACK_ERROR;
  140. goto out;
  141. }
  142. /* allocate new task now */
  143. task = slapi_new_task(slapi_entry_get_ndn(e));
  144. if (task == NULL) {
  145. slapi_log_err(SLAPI_LOG_ERR, "sampletask", "unable to allocate new task!\n");
  146. *returncode = LDAP_OPERATIONS_ERROR;
  147. rv = SLAPI_DSE_CALLBACK_ERROR;
  148. goto out;
  149. }
  150. /* set a destructor that will clean up myarg for us when the task is complete */
  151. slapi_task_set_destructor_fn(task, task_sampletask_destructor);
  152. /* Stash our argument in the task for use by the task thread */
  153. slapi_task_set_data(task, slapi_ch_strdup(myarg));
  154. /* start the sample task as a separate thread */
  155. thread = PR_CreateThread(PR_USER_THREAD, task_sampletask_thread,
  156. (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  157. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  158. if (thread == NULL) {
  159. slapi_log_err(SLAPI_LOG_ERR, "sampletask",
  160. "unable to create sample task thread!\n");
  161. *returncode = LDAP_OPERATIONS_ERROR;
  162. rv = SLAPI_DSE_CALLBACK_ERROR;
  163. slapi_task_finish(task, *returncode);
  164. } else {
  165. /* thread successful */
  166. rv = SLAPI_DSE_CALLBACK_OK;
  167. }
  168. out:
  169. return rv;
  170. }