user.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Server-side USER handles
  3. *
  4. * Copyright (C) 2001 Alexandre Julliard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include "thread.h"
  21. #include "user.h"
  22. #include "request.h"
  23. struct user_handle
  24. {
  25. void *ptr; /* pointer to object */
  26. unsigned short type; /* object type (0 if free) */
  27. unsigned short generation; /* generation counter */
  28. };
  29. static struct user_handle *handles;
  30. static struct user_handle *freelist;
  31. static int nb_handles;
  32. static int allocated_handles;
  33. static struct user_handle *handle_to_entry( user_handle_t handle )
  34. {
  35. unsigned short generation;
  36. int index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
  37. if (index < 0 || index >= nb_handles) return NULL;
  38. if (!handles[index].type) return NULL;
  39. generation = handle >> 16;
  40. if (generation == handles[index].generation || !generation || generation == 0xffff)
  41. return &handles[index];
  42. return NULL;
  43. }
  44. static inline user_handle_t entry_to_handle( struct user_handle *ptr )
  45. {
  46. unsigned int index = ptr - handles;
  47. return (index << 1) + FIRST_USER_HANDLE + (ptr->generation << 16);
  48. }
  49. static inline struct user_handle *alloc_user_entry(void)
  50. {
  51. struct user_handle *handle;
  52. if (freelist)
  53. {
  54. handle = freelist;
  55. freelist = handle->ptr;
  56. return handle;
  57. }
  58. if (nb_handles >= allocated_handles) /* need to grow the array */
  59. {
  60. struct user_handle *new_handles;
  61. /* grow array by 50% (but at minimum 32 entries) */
  62. int growth = max( 32, allocated_handles / 2 );
  63. int new_size = min( allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
  64. if (new_size <= allocated_handles) return NULL;
  65. if (!(new_handles = realloc( handles, new_size * sizeof(*handles) )))
  66. return NULL;
  67. handles = new_handles;
  68. allocated_handles = new_size;
  69. }
  70. handle = &handles[nb_handles++];
  71. handle->generation = 0;
  72. return handle;
  73. }
  74. static inline void *free_user_entry( struct user_handle *ptr )
  75. {
  76. void *ret;
  77. ret = ptr->ptr;
  78. ptr->ptr = freelist;
  79. ptr->type = 0;
  80. freelist = ptr;
  81. return ret;
  82. }
  83. /* allocate a user handle for a given object */
  84. user_handle_t alloc_user_handle( void *ptr, enum user_object type )
  85. {
  86. struct user_handle *entry = alloc_user_entry();
  87. if (!entry) return 0;
  88. entry->ptr = ptr;
  89. entry->type = type;
  90. if (++entry->generation >= 0xffff) entry->generation = 1;
  91. return entry_to_handle( entry );
  92. }
  93. /* return a pointer to a user object from its handle */
  94. void *get_user_object( user_handle_t handle, enum user_object type )
  95. {
  96. struct user_handle *entry;
  97. if (!(entry = handle_to_entry( handle )) || entry->type != type) return NULL;
  98. return entry->ptr;
  99. }
  100. /* get the full handle for a possibly truncated handle */
  101. user_handle_t get_user_full_handle( user_handle_t handle )
  102. {
  103. struct user_handle *entry;
  104. if (handle >> 16) return handle;
  105. if (!(entry = handle_to_entry( handle ))) return handle;
  106. return entry_to_handle( entry );
  107. }
  108. /* same as get_user_object plus set the handle to the full 32-bit value */
  109. void *get_user_object_handle( user_handle_t *handle, enum user_object type )
  110. {
  111. struct user_handle *entry;
  112. if (!(entry = handle_to_entry( *handle )) || entry->type != type) return NULL;
  113. *handle = entry_to_handle( entry );
  114. return entry->ptr;
  115. }
  116. /* free a user handle and return a pointer to the object */
  117. void *free_user_handle( user_handle_t handle )
  118. {
  119. struct user_handle *entry;
  120. if (!(entry = handle_to_entry( handle )))
  121. {
  122. set_error( STATUS_INVALID_HANDLE );
  123. return NULL;
  124. }
  125. return free_user_entry( entry );
  126. }
  127. /* return the next user handle after 'handle' that is of a given type */
  128. void *next_user_handle( user_handle_t *handle, enum user_object type )
  129. {
  130. struct user_handle *entry;
  131. if (!*handle) entry = handles;
  132. else
  133. {
  134. int index = ((*handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
  135. if (index < 0 || index >= nb_handles) return NULL;
  136. entry = handles + index + 1; /* start from the next one */
  137. }
  138. while (entry < handles + nb_handles)
  139. {
  140. if (!type || entry->type == type)
  141. {
  142. *handle = entry_to_handle( entry );
  143. return entry->ptr;
  144. }
  145. entry++;
  146. }
  147. return NULL;
  148. }
  149. /* free client-side user handles managed by the process */
  150. void free_process_user_handles( struct process *process )
  151. {
  152. unsigned int i;
  153. for (i = 0; i < nb_handles; i++)
  154. if (handles[i].type == USER_CLIENT && handles[i].ptr == process)
  155. free_user_entry( &handles[i] );
  156. }
  157. /* allocate an arbitrary user handle */
  158. DECL_HANDLER(alloc_user_handle)
  159. {
  160. reply->handle = alloc_user_handle( current->process, USER_CLIENT );
  161. }
  162. /* free an arbitrary user handle */
  163. DECL_HANDLER(free_user_handle)
  164. {
  165. struct user_handle *entry;
  166. if ((entry = handle_to_entry( req->handle )) && entry->type == USER_CLIENT)
  167. free_user_entry( entry );
  168. else
  169. set_error( STATUS_INVALID_HANDLE );
  170. }